Skip to content

Commit bdef325

Browse files
Merge remote-tracking branch 'origin/develop' into fb_sql_experiment
2 parents 8da2d0f + aee0f4a commit bdef325

49 files changed

Lines changed: 691 additions & 90 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/gwtsrc/org/labkey/api/gwt/client/model/GWTDomain.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class GWTDomain<FieldType extends GWTPropertyDescriptor> implements IsSer
4242
@Getter @Setter private boolean allowAttachmentProperties;
4343
@Getter @Setter private boolean allowFlagProperties;
4444
@Getter @Setter private boolean allowTextChoiceProperties;
45+
@Getter @Setter private boolean allowMultiChoiceProperties;
4546
@Getter @Setter private boolean allowSampleSubjectProperties;
4647
@Getter @Setter private boolean allowTimepointProperties;
4748
@Getter @Setter private boolean allowUniqueConstraintProperties;
@@ -90,6 +91,7 @@ public GWTDomain(GWTDomain<FieldType> src)
9091
this.allowAttachmentProperties = src.allowAttachmentProperties;
9192
this.allowFlagProperties = src.allowFlagProperties;
9293
this.allowTextChoiceProperties = src.allowTextChoiceProperties;
94+
this.allowMultiChoiceProperties = src.allowMultiChoiceProperties;
9395
this.allowSampleSubjectProperties = src.allowSampleSubjectProperties;
9496
this.allowTimepointProperties = src.allowTimepointProperties;
9597
this.allowUniqueConstraintProperties = src.allowUniqueConstraintProperties;

api/schemas/queryCustomView.xsd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@
9393

9494
<xsd:simpleType name="operatorType">
9595
<xsd:restriction base="xsd:string">
96+
<xsd:enumeration value="arraycontainsall"/>
97+
<xsd:enumeration value="arraycontainsany"/>
98+
<xsd:enumeration value="arraymatches"/>
99+
<xsd:enumeration value="arraynotmatches"/>
100+
<xsd:enumeration value="arraycontainsnone"/>
101+
<xsd:enumeration value="arrayisempty"/>
102+
<xsd:enumeration value="arrayisnotempty"/>
96103
<xsd:enumeration value="eq"/>
97104
<xsd:enumeration value="dateeq"/>
98105
<xsd:enumeration value="dateneq"/>

api/src/org/labkey/api/assay/AbstractAssayTsvDataHandler.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.labkey.api.data.ExpDataFileConverter;
3939
import org.labkey.api.data.ForeignKey;
4040
import org.labkey.api.data.ImportAliasable;
41+
import org.labkey.api.data.MultiChoice;
4142
import org.labkey.api.data.MvUtil;
4243
import org.labkey.api.data.RemapCache;
4344
import org.labkey.api.data.RuntimeSQLException;
@@ -863,7 +864,11 @@ else if (entry.getKey().equalsIgnoreCase(ProvenanceService.PROVENANCE_INPUT_PROP
863864
for (DomainProperty pd : columns)
864865
{
865866
Object o = map.get(pd.getName());
866-
if (o instanceof String)
867+
if (PropertyType.MULTI_CHOICE == pd.getPropertyType())
868+
{
869+
o = MultiChoice.Converter.getInstance().convert(MultiChoice.Array.class, o);
870+
}
871+
else if (o instanceof String)
867872
{
868873
o = StringUtils.trimToNull((String) o);
869874
map.put(pd.getName(), o);

api/src/org/labkey/api/data/CompareType.java

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,341 @@ public QClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
808808
}
809809
};
810810

811+
protected Collection getCollectionParam(Object value)
812+
{
813+
if (value instanceof Collection)
814+
{
815+
return (Collection)value;
816+
}
817+
else
818+
{
819+
List<String> values = new ArrayList<>();
820+
if (value != null)
821+
values.addAll(parseParams(value, getValueSeparator(), isNewLineSeparatorAllowed()));
822+
return values;
823+
}
824+
}
825+
826+
/** TODO:
827+
* <xsd:enumeration value="arrayisempty"/>
828+
* <xsd:enumeration value="arrayisnotempty"/>
829+
*/
830+
public static final CompareType ARRAY_CONTAINS_ALL = new CompareType("Contains All", "arraycontainsall", "ARRAYCONTAINSALL", true, null, OperatorType.ARRAYCONTAINSALL)
831+
{
832+
@Override
833+
public ArrayContainsAllClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
834+
{
835+
return new ArrayContainsAllClause(fieldKey, getCollectionParam(value));
836+
}
837+
838+
@Override
839+
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
840+
{
841+
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
842+
}
843+
844+
@Override
845+
public String getValueSeparator()
846+
{
847+
return ArrayClause.ARRAY_VALUE_SEPARATOR;
848+
}
849+
};
850+
851+
public static final CompareType ARRAY_CONTAINS_ANY = new CompareType("Contains Any", "arraycontainsany", "ARRAYCONTAINSANY", true, null, OperatorType.ARRAYCONTAINSANY)
852+
{
853+
@Override
854+
public ArrayContainsAnyClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
855+
{
856+
return new ArrayContainsAnyClause(fieldKey, getCollectionParam(value));
857+
}
858+
859+
@Override
860+
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
861+
{
862+
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
863+
}
864+
865+
@Override
866+
public String getValueSeparator()
867+
{
868+
return ArrayClause.ARRAY_VALUE_SEPARATOR;
869+
}
870+
};
871+
872+
public static final CompareType ARRAY_CONTAINS_NONE = new CompareType("Contains None", "arraycontainsnone", "ARRAYCONTAINSNONE", true, null, OperatorType.ARRAYCONTAINSNONE)
873+
{
874+
@Override
875+
public ArrayContainsNoneClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
876+
{
877+
return new ArrayContainsNoneClause(fieldKey, getCollectionParam(value));
878+
}
879+
880+
@Override
881+
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
882+
{
883+
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
884+
}
885+
886+
@Override
887+
public String getValueSeparator()
888+
{
889+
return ArrayClause.ARRAY_VALUE_SEPARATOR;
890+
}
891+
};
892+
893+
public static final CompareType ARRAY_MATCHES = new CompareType("Contains Exactly", "arraymatches", "ARRAYMATCHES", true, null, OperatorType.ARRAYMATCHES)
894+
{
895+
@Override
896+
public ArrayMatchesClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
897+
{
898+
return new ArrayMatchesClause(fieldKey, getCollectionParam(value));
899+
}
900+
901+
@Override
902+
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
903+
{
904+
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
905+
}
906+
907+
@Override
908+
public String getValueSeparator()
909+
{
910+
return ArrayClause.ARRAY_VALUE_SEPARATOR;
911+
}
912+
};
913+
914+
public static final CompareType ARRAY_NOT_MATCHES = new CompareType("Does Not Contain Exactly", "arraynotmatches", "ARRAYNOTMATCHES", true, null, OperatorType.ARRAYNOTMATCHES)
915+
{
916+
@Override
917+
public ArrayNotMatchesClause createFilterClause(@NotNull FieldKey fieldKey, Object value)
918+
{
919+
return new ArrayNotMatchesClause(fieldKey, getCollectionParam(value));
920+
}
921+
922+
@Override
923+
public boolean meetsCriteria(ColumnRenderProperties col, Object value, Object[] filterValues)
924+
{
925+
throw new UnsupportedOperationException("Conditional formatting not yet supported for Multi Choices");
926+
}
927+
928+
@Override
929+
public String getValueSeparator()
930+
{
931+
return ArrayClause.ARRAY_VALUE_SEPARATOR;
932+
}
933+
};
934+
935+
public static abstract class ArrayClause extends SimpleFilter.MultiValuedFilterClause
936+
{
937+
public static final String ARRAY_VALUE_SEPARATOR = ",";
938+
939+
public ArrayClause(@NotNull FieldKey fieldKey, CompareType comparison, Collection<?> params, boolean negated)
940+
{
941+
super(fieldKey, comparison, params, negated);
942+
}
943+
944+
public SQLFragment[] getParamSQLFragments(SqlDialect dialect)
945+
{
946+
Object[] params = getParamVals();
947+
SQLFragment[] fragments = new SQLFragment[params.length];
948+
949+
JdbcType type = null;
950+
// Try to infer the type from the first non-null parameter
951+
for (Object param : params)
952+
{
953+
if (param != null)
954+
{
955+
type = JdbcType.valueOf(param.getClass());
956+
break;
957+
}
958+
}
959+
960+
for (int i = 0; i < params.length; i++)
961+
fragments[i] = new SQLFragment().append(escapeLabKeySqlValue(params[i], type));
962+
963+
return fragments;
964+
}
965+
966+
public Pair<SQLFragment, SQLFragment> getSqlFragments(Map<FieldKey, ? extends ColumnInfo> columnMap, SqlDialect dialect)
967+
{
968+
SQLFragment[] paramValues = getParamSQLFragments(dialect);
969+
970+
if (paramValues == null || paramValues.length == 0)
971+
return null;
972+
973+
ColumnInfo colInfo = columnMap != null ? columnMap.get(_fieldKey) : null;
974+
var alias = SimpleFilter.getAliasForColumnFilter(dialect, colInfo, _fieldKey);
975+
976+
SQLFragment valuesFragment = dialect.array_construct(paramValues);
977+
SQLFragment columnFragment = new SQLFragment().appendIdentifier(alias);
978+
979+
return new Pair<>(valuesFragment, columnFragment);
980+
}
981+
982+
}
983+
984+
private static class ArrayContainsAllClause extends ArrayClause
985+
{
986+
987+
public ArrayContainsAllClause(@NotNull FieldKey fieldKey, Collection<?> params)
988+
{
989+
super(fieldKey, CompareType.ARRAY_CONTAINS_ALL, params, false);
990+
}
991+
992+
@Override
993+
public SQLFragment toSQLFragment(Map<FieldKey, ? extends ColumnInfo> columnMap, SqlDialect dialect)
994+
{
995+
Pair<SQLFragment, SQLFragment> valueFieldSql = getSqlFragments(columnMap, dialect);
996+
if (valueFieldSql == null)
997+
return new SQLFragment("1=2");
998+
999+
return dialect.array_all_in_array(valueFieldSql.first, valueFieldSql.second);
1000+
}
1001+
1002+
@Override
1003+
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
1004+
{
1005+
return "array_contains_all(" + getLabKeySQLColName(_fieldKey) + ", " + getParamVals()[0] + ")";
1006+
}
1007+
1008+
@Override
1009+
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
1010+
{
1011+
Object[] params = getParamVals();
1012+
sb.append("contains all of ").append(Arrays.toString(params));
1013+
}
1014+
1015+
}
1016+
1017+
private static class ArrayContainsAnyClause extends ArrayClause
1018+
{
1019+
1020+
public ArrayContainsAnyClause(@NotNull FieldKey fieldKey, CompareType comparison, Collection<?> params, boolean negated)
1021+
{
1022+
super(fieldKey, comparison, params, negated);
1023+
}
1024+
1025+
public ArrayContainsAnyClause(@NotNull FieldKey fieldKey, Collection<?> params)
1026+
{
1027+
this(fieldKey, CompareType.ARRAY_CONTAINS_ANY, params, false);
1028+
}
1029+
1030+
@Override
1031+
public SQLFragment toSQLFragment(Map<FieldKey, ? extends ColumnInfo> columnMap, SqlDialect dialect)
1032+
{
1033+
Pair<SQLFragment, SQLFragment> valueFieldSql = getSqlFragments(columnMap, dialect);
1034+
if (valueFieldSql == null)
1035+
return new SQLFragment("1=2");
1036+
1037+
SQLFragment sql = dialect.array_some_in_array(valueFieldSql.first, valueFieldSql.second);
1038+
if (!_negated)
1039+
return sql;
1040+
return new SQLFragment(" NOT (").append(sql).append(")");
1041+
}
1042+
1043+
@Override
1044+
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
1045+
{
1046+
return "array_contains_any(" + getLabKeySQLColName(_fieldKey) + ", " + getParamVals()[0] + ")";
1047+
}
1048+
1049+
@Override
1050+
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
1051+
{
1052+
Object[] params = getParamVals();
1053+
sb.append("contains at least one of ").append(Arrays.toString(params));
1054+
}
1055+
1056+
}
1057+
1058+
private static class ArrayContainsNoneClause extends ArrayContainsAnyClause
1059+
{
1060+
1061+
public ArrayContainsNoneClause(@NotNull FieldKey fieldKey, Collection<?> params)
1062+
{
1063+
super(fieldKey, CompareType.ARRAY_CONTAINS_NONE, params, true);
1064+
}
1065+
1066+
@Override
1067+
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
1068+
{
1069+
return "array_contains_none(" + getLabKeySQLColName(_fieldKey) + ", " + getParamVals()[0] + ")";
1070+
}
1071+
1072+
@Override
1073+
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
1074+
{
1075+
Object[] params = getParamVals();
1076+
sb.append("contains none of ").append(Arrays.toString(params));
1077+
}
1078+
1079+
}
1080+
1081+
private static class ArrayMatchesClause extends ArrayClause
1082+
{
1083+
1084+
public ArrayMatchesClause(@NotNull FieldKey fieldKey, CompareType comparison, Collection<?> params, boolean negated)
1085+
{
1086+
super(fieldKey, comparison, params, negated);
1087+
}
1088+
1089+
public ArrayMatchesClause(@NotNull FieldKey fieldKey, Collection<?> params)
1090+
{
1091+
this(fieldKey, CompareType.ARRAY_MATCHES, params, false);
1092+
}
1093+
1094+
@Override
1095+
public SQLFragment toSQLFragment(Map<FieldKey, ? extends ColumnInfo> columnMap, SqlDialect dialect)
1096+
{
1097+
Pair<SQLFragment, SQLFragment> valueFieldSql = getSqlFragments(columnMap, dialect);
1098+
if (valueFieldSql == null)
1099+
return new SQLFragment("1=2");
1100+
1101+
SQLFragment sql = dialect.array_same_array(valueFieldSql.first, valueFieldSql.second);
1102+
if (!_negated)
1103+
return sql;
1104+
return new SQLFragment(" NOT (").append(sql).append(")");
1105+
}
1106+
1107+
@Override
1108+
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
1109+
{
1110+
return "array_is_same(" + getLabKeySQLColName(_fieldKey) + ", " + getParamVals()[0] + ")";
1111+
}
1112+
1113+
@Override
1114+
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
1115+
{
1116+
Object[] params = getParamVals();
1117+
sb.append("contains the same elements as ").append(Arrays.toString(params));
1118+
}
1119+
1120+
}
1121+
1122+
private static class ArrayNotMatchesClause extends ArrayMatchesClause
1123+
{
1124+
1125+
public ArrayNotMatchesClause(@NotNull FieldKey fieldKey, Collection<?> params)
1126+
{
1127+
super(fieldKey, CompareType.ARRAY_NOT_MATCHES, params, true);
1128+
}
1129+
1130+
@Override
1131+
public String getLabKeySQLWhereClause(Map<FieldKey, ? extends ColumnInfo> columnMap)
1132+
{
1133+
return "NOT array_is_same(" + getLabKeySQLColName(_fieldKey) + ", " + getParamVals()[0] + ")";
1134+
}
1135+
1136+
@Override
1137+
public void appendFilterText(StringBuilder sb, ColumnNameFormatter formatter)
1138+
{
1139+
Object[] params = getParamVals();
1140+
sb.append("does not contain the same elements as ").append(Arrays.toString(params));
1141+
}
1142+
1143+
}
1144+
1145+
8111146
private static class QClause extends CompareType.CompareClause
8121147
{
8131148
private List<ColumnInfo> _queryColumns = null;

0 commit comments

Comments
 (0)