com.hcl.domino.dql.DQL Maven / Gradle / Ivy
/*
* ==========================================================================
* Copyright (C) 2019-2022 HCL America, Inc. ( http://www.hcl.com/ )
* All rights reserved.
* ==========================================================================
* Licensed under the Apache License, Version 2.0 (the "License"). You may
* not use this file except in compliance with the License. You may obtain a
* copy of the License at .
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* ==========================================================================
*/
package com.hcl.domino.dql;
import java.text.MessageFormat;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Collection;
import java.util.Date;
import java.util.Objects;
import com.hcl.domino.data.DominoDateTime;
import com.hcl.domino.data.Formula;
import com.hcl.domino.util.JNXStringUtil;
/**
* Utility class to programmatically compose syntactically correct
* DQL queries and prevent malicous content injection (we hopefully
* catch all possible threats like using quote characters in search
* values).
*
* For best code quality, use a static import like this
*
*
* import static com.hcl.domino.dql.DQL.*;
*
*
*
* to import all static methods of this class.
* Then you can use methods like {@link #item(String)}, {@link #in(String...)},
* {@link #inAll(String...)} or {@link #view(String)}
* directly without the prefix DQL."
:
*
*
* DQLTerm dqlQuery = and(
* item("Lastname").isEqualTo("Abbott"),
* item("Firstname").isGreaterThan("B")
* );
*
*
* To see the resulting DQL query string, simple call
* {@link DQLTerm#toString()}.
*/
public class DQL {
public static class AllTerm extends DQLTerm {
@Override
public String toString() {
return "@all"; //$NON-NLS-1$
}
}
public static class AndTerm extends DQLTerm {
private final DQLTerm[] m_terms;
private String m_toString;
private AndTerm(final DQLTerm[] terms) {
if (terms == null) {
throw new IllegalArgumentException("And arguments value is null");
}
if (terms.length == 0) {
throw new IllegalArgumentException("And arguments value is empty");
}
this.m_terms = terms;
}
@Override
public String toString() {
if (this.m_terms.length == 1) {
return this.m_terms[0].toString();
}
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.m_terms.length; i++) {
if (i > 0) {
sb.append(" and "); //$NON-NLS-1$
}
if (this.m_terms[i] instanceof OrTerm) {
sb.append("("); //$NON-NLS-1$
sb.append(this.m_terms[i].toString());
sb.append(")"); //$NON-NLS-1$
} else if (this.m_terms[i] instanceof AndTerm) {
sb.append(this.m_terms[i].toString());
} else {
sb.append(this.m_terms[i]);
}
}
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
/**
* Base class for a variety of DQL search terms
*/
public static abstract class DQLTerm {
/**
* Returns the term content as DQL query
*
* @return DQL
*/
@Override
public abstract String toString();
@Override
public boolean equals(Object obj) {
return obj != null && getClass().equals(obj.getClass()) && toString().equals(obj.toString());
}
}
public static class InViewsOrFoldersTerm extends DQLTerm {
private final String[] m_viewNames;
private final boolean m_matchAll;
private String m_toString;
private InViewsOrFoldersTerm(final String[] viewNames, final boolean matchAll) {
this.m_viewNames = viewNames;
this.m_matchAll = matchAll;
}
@Override
public String toString() {
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
sb.append("in "); //$NON-NLS-1$
if (this.m_matchAll) {
sb.append("all "); //$NON-NLS-1$
}
sb.append("("); //$NON-NLS-1$
for (int i = 0; i < this.m_viewNames.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append("'"); //$NON-NLS-1$
sb.append(DQL.escapeViewName(this.m_viewNames[i]));
sb.append("'"); //$NON-NLS-1$
}
sb.append(")"); //$NON-NLS-1$
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
public static class NamedItem extends Subject {
private final String m_itemName;
private NamedItem(final String itemName) {
this.m_itemName = itemName;
}
public String getName() {
return this.m_itemName;
}
@Override
public String toString() {
return DQL.escapeItemName(this.m_itemName);
}
}
public static class NamedView {
private final String m_viewName;
private NamedView(final String viewName) {
this.m_viewName = viewName;
}
/**
* Method to define the column for which we want to
* filter the value
*
* @param columnName view column name
* @return object to define the column value and relation (e.g. isEqualTo)
*/
public NamedViewColumn column(final String columnName) {
return new NamedViewColumn(this, columnName);
}
public String getViewName() {
return this.m_viewName;
}
@Override
public String toString() {
return this.m_viewName;
}
}
public static class NamedViewColumn extends Subject {
private final NamedView m_view;
private final String m_columnName;
private String m_toString;
private NamedViewColumn(final NamedView view, final String columnName) {
this.m_view = view;
this.m_columnName = columnName;
}
public String getColumnName() {
return this.m_columnName;
}
@Override
public String toString() {
if (this.m_toString == null) {
this.m_toString = MessageFormat.format("''{0}''.{1}", DQL.escapeViewName(this.m_view.getViewName()), //$NON-NLS-1$
DQL.escapeColumnName(this.m_columnName));
}
return this.m_toString;
}
}
public static class NoteContainsTerm extends DQLTerm {
private final boolean m_containsAll;
private final String[] m_values;
private String m_toString;
public NoteContainsTerm(final boolean containsAll, final String... values) {
this.m_containsAll = containsAll;
this.m_values = values;
}
@Override
public String toString() {
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
sb.append("contains "); //$NON-NLS-1$
if (this.m_containsAll) {
sb.append("all "); //$NON-NLS-1$
}
sb.append("("); //$NON-NLS-1$
for (int i = 0; i < this.m_values.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append("'"); //$NON-NLS-1$
sb.append(DQL.escapeStringValue(this.m_values[i]));
sb.append("'"); //$NON-NLS-1$
}
sb.append(")"); //$NON-NLS-1$
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
public static class NotTerm extends DQLTerm {
private final DQLTerm m_term;
private String m_toString;
private NotTerm(final DQLTerm term) {
this.m_term = term;
}
@Override
public String toString() {
if (this.m_toString == null) {
if (this.m_term instanceof AndTerm || this.m_term instanceof OrTerm) {
this.m_toString = MessageFormat.format("not ({0})", this.m_term.toString()); //$NON-NLS-1$
} else {
this.m_toString = MessageFormat.format("not {0}", this.m_term.toString()); //$NON-NLS-1$
}
}
return this.m_toString;
}
}
public static class OrTerm extends DQLTerm {
private final DQLTerm[] m_terms;
private String m_toString;
private OrTerm(final DQLTerm[] terms) {
if (terms == null) {
throw new IllegalArgumentException("Or arguments value is null");
}
if (terms.length == 0) {
throw new IllegalArgumentException("Or arguments value is empty");
}
this.m_terms = terms;
}
@Override
public String toString() {
if (this.m_terms.length == 1) {
return this.m_terms[0].toString();
}
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.m_terms.length; i++) {
if (i > 0) {
sb.append(" or "); //$NON-NLS-1$
}
if (this.m_terms[i] instanceof OrTerm) {
sb.append(this.m_terms[i].toString());
} else if (this.m_terms[i] instanceof AndTerm) {
// sb.append("(");
sb.append(this.m_terms[i].toString());
// sb.append(")");
} else {
sb.append(this.m_terms[i]);
}
}
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
/**
* @since 1.1.2
*/
public static class FormulaTerm extends DQLTerm {
private final String m_formula;
private String m_toString;
private FormulaTerm(final String formula) {
if(formula == null || formula.isEmpty()) {
throw new IllegalArgumentException("Formula expression cannot be empty");
}
this.m_formula = formula;
}
@Override
public String toString() {
if (this.m_toString == null) {
String escapedFormula = m_formula.replace("'", "\\'"); //$NON-NLS-1$ //$NON-NLS-2$
this.m_toString = MessageFormat.format("@formula(''{0}'')", escapedFormula); //$NON-NLS-1$
}
return this.m_toString;
}
}
public static class SpecialValue extends NamedItem {
private final SpecialValueType m_type;
private SpecialValue(final SpecialValueType type) {
super(type.getValue());
this.m_type = type;
}
public SpecialValueType getType() {
return this.m_type;
}
@Override
public String toString() {
return this.m_type.getValue();
}
}
private enum SpecialValueType {
MODIFIEDINTHISFLE("@ModifiedInThisFile"), //$NON-NLS-1$
DOCUMENTUNIQUEID("@DocumentUniqueID"), //$NON-NLS-1$
CREATED("@Created"); //$NON-NLS-1$
private final String m_value;
SpecialValueType(final String value) {
this.m_value = value;
}
public String getValue() {
return this.m_value;
}
}
private static class Subject {
/**
* Returns a DQL term to run a FT search on the value of an item with one or
* multiple search words.
*
* @param searchWords search words with optional wildcards like Lehm* or Lehman?
* @return term
* @since Domino R11
*/
public ValueContainsTerm contains(final String... searchWords) {
return new ValueContainsTerm(this, false, searchWords);
}
/**
* Returns a DQL term to run a FT search on the value of an item with one or
* multiple search words.
* All search words must exist in the note for it to be a match.
*
* @param searchWords search words with optional wildcards like Lehm* or Lehman?
* @return term
* @since Domino R11
*/
public ValueContainsTerm containsAll(final String... searchWords) {
return new ValueContainsTerm(this, true, searchWords);
}
public ValueComparisonTerm in(final Collection values, final Class clazz) {
if (Integer.class == clazz) {
final int[] valuesArr = new int[values.size()];
int idx = 0;
for (final T currVal : values) {
valuesArr[idx++] = ((Number) currVal).intValue();
}
return this.in(valuesArr);
} else if (Double.class == clazz) {
final double[] valuesArr = new double[values.size()];
int idx = 0;
for (final T currVal : values) {
valuesArr[idx++] = ((Number) currVal).doubleValue();
}
return this.in(valuesArr);
} else if (String.class == clazz) {
final String[] valuesArr = new String[values.size()];
int idx = 0;
for (final T currVal : values) {
valuesArr[idx++] = (String) currVal;
}
return this.in(valuesArr);
} else {
throw new IllegalArgumentException(
MessageFormat.format("Unsupported class type: {0}. Try Integer, Double or String.", clazz.getName()));
}
}
public ValueComparisonTerm in(final double... dblValues) {
Objects.requireNonNull(dblValues, "Values list cannot be null");
if (dblValues.length == 0) {
throw new IllegalArgumentException("Values list cannot be empty");
}
return new ValueComparisonTerm(this, TermRelation.IN, dblValues);
}
public ValueComparisonTerm in(final int... intValues) {
Objects.requireNonNull(intValues, "Values list cannot be null");
if (intValues.length == 0) {
throw new IllegalArgumentException("Values list cannot be empty");
}
return new ValueComparisonTerm(this, TermRelation.IN, intValues);
}
public ValueComparisonTerm in(final String... strValues) {
Objects.requireNonNull(strValues, "Values list cannot be null");
if (strValues.length == 0) {
throw new IllegalArgumentException("Values list cannot be empty");
}
return new ValueComparisonTerm(this, TermRelation.IN, strValues);
}
public ValueComparisonTerm isEqualTo(final Date dtVal) {
return new ValueComparisonTerm(this, TermRelation.EQUAL, dtVal);
}
public ValueComparisonTerm isEqualTo(final double numVal) {
return new ValueComparisonTerm(this, TermRelation.EQUAL, Double.valueOf(numVal));
}
public ValueComparisonTerm isEqualTo(final int numVal) {
return new ValueComparisonTerm(this, TermRelation.EQUAL, Integer.valueOf(numVal));
}
public ValueComparisonTerm isEqualTo(final String strVal) {
return new ValueComparisonTerm(this, TermRelation.EQUAL, strVal);
}
public ValueComparisonTerm isEqualTo(final TemporalAccessor tdVal) {
return new ValueComparisonTerm(this, TermRelation.EQUAL, tdVal);
}
public ValueComparisonTerm isGreaterThan(final Date dtVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHAN, dtVal);
}
public ValueComparisonTerm isGreaterThan(final double numVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHAN, Double.valueOf(numVal));
}
public ValueComparisonTerm isGreaterThan(final int numVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHAN, Integer.valueOf(numVal));
}
public ValueComparisonTerm isGreaterThan(final String strVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHAN, strVal);
}
public ValueComparisonTerm isGreaterThan(final TemporalAccessor tdVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHAN, tdVal);
}
public ValueComparisonTerm isGreaterThanOrEqual(final Date dtVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHANOREQUAL, dtVal);
}
public ValueComparisonTerm isGreaterThanOrEqual(final double numVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHANOREQUAL, Double.valueOf(numVal));
}
public ValueComparisonTerm isGreaterThanOrEqual(final int numVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHANOREQUAL, Integer.valueOf(numVal));
}
public ValueComparisonTerm isGreaterThanOrEqual(final String strVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHANOREQUAL, strVal);
}
public ValueComparisonTerm isGreaterThanOrEqual(final TemporalAccessor tdVal) {
return new ValueComparisonTerm(this, TermRelation.GREATERTHANOREQUAL, tdVal);
}
public ValueComparisonTerm isLessThan(final Date dtVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHAN, dtVal);
}
public ValueComparisonTerm isLessThan(final double numVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHAN, Double.valueOf(numVal));
}
public ValueComparisonTerm isLessThan(final int numVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHAN, Integer.valueOf(numVal));
}
public ValueComparisonTerm isLessThan(final String strVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHAN, strVal);
}
public ValueComparisonTerm isLessThan(final TemporalAccessor tdVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHAN, tdVal);
}
public ValueComparisonTerm isLessThanOrEqual(final Date dtVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHANOREQUAL, dtVal);
}
public ValueComparisonTerm isLessThanOrEqual(final double numVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHANOREQUAL, Double.valueOf(numVal));
}
public ValueComparisonTerm isLessThanOrEqual(final int numVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHANOREQUAL, Integer.valueOf(numVal));
}
public ValueComparisonTerm isLessThanOrEqual(final String strVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHANOREQUAL, strVal);
}
public ValueComparisonTerm isLessThanOrEqual(final TemporalAccessor tdVal) {
return new ValueComparisonTerm(this, TermRelation.LESSTHANOREQUAL, tdVal);
}
}
private enum TermRelation {
EQUAL("="), //$NON-NLS-1$
LESSTHAN("<"), //$NON-NLS-1$
LESSTHANOREQUAL("<="), //$NON-NLS-1$
GREATERTHAN(">"), //$NON-NLS-1$
GREATERTHANOREQUAL(">="), //$NON-NLS-1$
IN("in"), //$NON-NLS-1$
INALL("in all"), //$NON-NLS-1$
CONTAINS("contains"); //$NON-NLS-1$
private final String m_val;
TermRelation(final String val) {
this.m_val = val;
}
public String getValue() {
return this.m_val;
}
}
public static class ValueComparisonTerm extends DQLTerm {
private final Subject m_subject;
private final TermRelation m_relation;
private final Object m_value;
private String m_toString;
private ValueComparisonTerm(final Subject item, final TermRelation relation, final Object value) {
this.m_subject = item;
this.m_relation = relation;
this.m_value = value;
}
@Override
public String toString() {
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
sb.append(this.m_subject.toString());
sb.append(" "); //$NON-NLS-1$
sb.append(this.m_relation.getValue());
sb.append(" "); //$NON-NLS-1$
if (this.m_relation == TermRelation.IN) {
sb.append("("); //$NON-NLS-1$
}
if (this.m_value instanceof String[]) {
final String[] strValues = (String[]) this.m_value;
for (int i = 0; i < strValues.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append("'"); //$NON-NLS-1$
sb.append(DQL.escapeStringValue(strValues[i]));
sb.append("'"); //$NON-NLS-1$
}
} else if (this.m_value instanceof int[]) {
final int[] intValues = (int[]) this.m_value;
for (int i = 0; i < intValues.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append(Integer.toString(intValues[i]));
}
} else if (this.m_value instanceof double[]) {
final double[] dblValues = (double[]) this.m_value;
for (int i = 0; i < dblValues.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append(DQL.formatDoubleValue(dblValues[i]));
}
} else if (this.m_value instanceof Date[]) {
final Date[] dateValues = (Date[]) this.m_value;
for (int i = 0; i < dateValues.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append(DQL.formatDateValue(dateValues[i]));
}
} else if (this.m_value instanceof DominoDateTime[]) {
final DominoDateTime[] tdValues = (DominoDateTime[]) this.m_value;
for (int i = 0; i < tdValues.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append(DQL.formatDominoDateTimeValue(tdValues[i]));
}
} else if (this.m_value instanceof String) {
sb
.append("'") //$NON-NLS-1$
.append(DQL.escapeStringValue((String) this.m_value))
.append("'"); //$NON-NLS-1$
} else if (this.m_value instanceof Integer) {
sb.append(this.m_value);
} else if (this.m_value instanceof Double) {
sb.append(DQL.formatDoubleValue((Double) this.m_value));
} else if (this.m_value instanceof Date) {
sb.append(DQL.formatDateValue((Date) this.m_value));
} else if (this.m_value instanceof DominoDateTime) {
sb.append(DQL.formatDominoDateTimeValue((DominoDateTime) this.m_value));
} else if(this.m_value instanceof TemporalAccessor) {
sb.append(DQL.formatTemporalValue((TemporalAccessor) this.m_value));
} else {
throw new IllegalArgumentException(MessageFormat.format("Unknown value found: {0} (type={1})", this.m_value,
this.m_value == null ? "null" : this.m_value.getClass().getName())); //$NON-NLS-1$
}
if (this.m_relation == TermRelation.IN) {
sb.append(")"); //$NON-NLS-1$
}
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
public static class ValueContainsTerm extends DQLTerm {
private final Subject m_subject;
private final boolean m_containsAll;
private final String[] m_values;
private String m_toString;
private ValueContainsTerm(final Subject item, final boolean containsAll, final String[] values) {
this.m_subject = item;
this.m_containsAll = containsAll;
this.m_values = values;
}
@Override
public String toString() {
if (this.m_toString == null) {
final StringBuilder sb = new StringBuilder();
sb.append(this.m_subject.toString());
sb.append(" contains "); //$NON-NLS-1$
if (this.m_containsAll) {
sb.append("all "); //$NON-NLS-1$
}
sb.append("("); //$NON-NLS-1$
for (int i = 0; i < this.m_values.length; i++) {
if (i > 0) {
sb.append(", "); //$NON-NLS-1$
}
sb.append("'"); //$NON-NLS-1$
sb.append(DQL.escapeStringValue(this.m_values[i]));
sb.append("'"); //$NON-NLS-1$
}
sb.append(")"); //$NON-NLS-1$
this.m_toString = sb.toString();
}
return this.m_toString;
}
}
/**
* Returns a DQL term that matches all documents
*
* @return term
*/
public static DQLTerm all() {
return new AllTerm();
}
/**
* Returns a DQL term to do an AND operation on multiple other terms
*
* @param terms terms for AND operation
* @return AND term
*/
public static DQLTerm and(final DQLTerm... terms) {
return new AndTerm(terms);
}
/**
* Returns a DQL term to run a FT search on the whole note with one or multiple
* search words.
*
* @param values search words with optional wildcards like Lehm* or Lehman?
* @return term
* @since Domino R11
*/
public static DQLTerm contains(final String... values) {
return new NoteContainsTerm(false, values);
}
/**
* Returns a DQL term to run a FT search on the whole note with one or multiple
* search words.
* All search words must exist in the note for it to be a match.
*
* @param values search words with optional wildcards like Lehm* or Lehman?
* @return term
* @since Domino R11
*/
public static DQLTerm containsAll(final String... values) {
return new NoteContainsTerm(true, values);
}
/**
* Use this method to filter by @Created value
*
* @return object to define the creation date to compare with and relation (e.g.
* isGreaterThan)
*/
public static SpecialValue created() {
return new SpecialValue(SpecialValueType.CREATED);
}
/**
* Use this method to filter by @DocumentUniqueId value
*
* @return object to define the UNID and isEqual relation
*/
public static SpecialValue documentUniqueId() {
return new SpecialValue(SpecialValueType.DOCUMENTUNIQUEID);
}
private static String escapeColumnName(final String columnName) {
if (columnName.contains(" ")) { //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat.format("Unexpected whitespace found in view name: {0}", columnName));
}
if (columnName.contains("'") || columnName.contains("\"")) { //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat.format("Unexpected quote character in view name: {0}", columnName));
}
return columnName.replace("\\", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$
}
private static String escapeItemName(final String itemName) {
if (itemName.contains(" ")) { //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat.format("Unexpected whitespace found in item name: {0}", itemName));
}
if (itemName.contains("'") || itemName.contains("\"")) { //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat.format("Unexpected quote character in item name: {0}", itemName));
}
return itemName;
}
private static String escapeStringValue(final String strVal) {
if (strVal.contains("\n")) { //$NON-NLS-1$
throw new IllegalArgumentException(MessageFormat.format("Unexpected newline character in string value: {0}", strVal));
}
return strVal
.replace("'", "''"); //$NON-NLS-1$ //$NON-NLS-2$
}
private static String escapeViewName(final String viewName) {
if (viewName.contains("'") || viewName.contains("\"")) { //$NON-NLS-1$ //$NON-NLS-2$
throw new IllegalArgumentException(MessageFormat.format("Unexpected quote character in view name: {0}", viewName));
}
return viewName.replace("\\", "\\\\"); //$NON-NLS-1$ //$NON-NLS-2$
}
private static String formatDateValue(final Date dateValue) {
//Domino can only store hundredth of a second
long dateValueMS = dateValue.getTime();
long millis = dateValue.getTime() % 1000;
long millisRounded = 10 * (millis / 10);
dateValueMS -= (millis-millisRounded);
return MessageFormat.format("@dt(''{0}'')", DateTimeFormatter.ISO_DATE_TIME.format(OffsetDateTime.ofInstant(Instant.ofEpochMilli(dateValueMS), ZoneId.of("UTC")))); //$NON-NLS-1$ //$NON-NLS-2$
}
private static String formatDominoDateTimeValue(final DominoDateTime tdValue) {
if (tdValue.hasDate()) {
if (tdValue.hasTime()) {
return MessageFormat.format("@dt(''{0}'')", DateTimeFormatter.ISO_DATE_TIME.format(tdValue.toOffsetDateTime())); //$NON-NLS-1$
} else {
return DateTimeFormatter.ISO_LOCAL_DATE.format(tdValue.toOffsetDateTime().toInstant());
}
} else {
if (tdValue.hasTime()) {
return DateTimeFormatter.ISO_LOCAL_TIME.format(tdValue.toOffsetDateTime().toInstant());
} else {
throw new IllegalArgumentException("DominoDateTime has no date and no time");
}
}
}
private static String formatTemporalValue(final TemporalAccessor temporalValue) {
// TODO see if there's a more-efficient way to identify the type
try {
OffsetDateTime dt = OffsetDateTime.from(temporalValue);
LocalDate localDate = dt.toLocalDate();
LocalTime localTime = toHundredths(dt.toLocalTime());
OffsetDateTime rounded = OffsetDateTime.of(localDate, localTime, dt.getOffset());
return MessageFormat.format("@dt(''{0}'')", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(rounded)); //$NON-NLS-1$
} catch(DateTimeException e) {
// Next
}
try {
LocalDate dt = LocalDate.from(temporalValue);
return MessageFormat.format("@dt(''{0}'')", DateTimeFormatter.ISO_LOCAL_DATE.format(dt)); //$NON-NLS-1$
} catch(DateTimeException e) {
// Next
}
try {
LocalTime dt = LocalTime.from(temporalValue);
LocalTime hundredths = toHundredths(dt);
return MessageFormat.format("@dt(''{0}'')", DateTimeFormatter.ISO_LOCAL_TIME.format(hundredths)); //$NON-NLS-1$
} catch(DateTimeException e) {
// Next
}
Instant instant = Instant.from(temporalValue);
return formatDateValue(Date.from(instant));
}
private static LocalTime toHundredths(LocalTime localTime) {
int millis = localTime.getNano() / 1000 / 1000;
millis = millis / 10 * 10;
return LocalTime.of(localTime.getHour(), localTime.getMinute(), localTime.getSecond(), millis * 1000 * 1000);
}
private static String formatDoubleValue(final double dblValue) {
return Double.toString(dblValue);
}
/**
* Creates a search term to find documents that exist in at least
* one of the specified views.
*
* @param views view names (V10.0 does not support alias names)
* @return DQL term
*/
public static InViewsOrFoldersTerm in(final String... views) {
return new InViewsOrFoldersTerm(views, false);
}
/**
* Creates a search term to find documents that exist in multiple
* views
*
* @param views view names (V10.0 does not support alias names)
* @return DQL term
*/
public static InViewsOrFoldersTerm inAll(final String... views) {
return new InViewsOrFoldersTerm(views, true);
}
/**
* Use this method to filter for documents with a specific item
* value
*
* @param itemName item name
* @return object to define the item value and relation (e.g. isEqual to)
*/
public static NamedItem item(final String itemName) {
return new NamedItem(itemName);
}
/**
* Use this method to filter by @ModifiedInThisFile value
*
* @return object to define a date value and relation (e.g. isGreaterThan /
* isLess)
*/
public static SpecialValue modifiedInThisFile() {
return new SpecialValue(SpecialValueType.MODIFIEDINTHISFLE);
}
/**
* Returns a DQL term to negate the specified term
*
* @param term term to negate
* @return negated term
*/
public static DQLTerm not(final DQLTerm term) {
return new NotTerm(term);
}
/**
* Returns a DQL term to do an OR operation on multiple other terms
*
* @param terms terms for OR operation
* @return OR term
*/
public static DQLTerm or(final DQLTerm... terms) {
return new OrTerm(terms);
}
/**
* Use this method to filter for documents with a specific view
* column value
*
* @param viewName view name
* @return object to define which column to filter
*/
public static NamedView view(final String viewName) {
return new NamedView(viewName);
}
/**
* Use this method to filter documents based on a formula-language
* expression
*
* @param formula the formula expression to use
* @return term representing the formula expression
* @throws IllegalArgumentException if {@code formula} is empty
* @since 1.1.2
*/
public static FormulaTerm formula(String formula) {
return new FormulaTerm(formula);
}
/**
* Use this method to filter documents based on a formula-language
* expression
*
* @param formula the {@link Formula} objects to use
* @return term representing the formula expression
* @throws NullPointerException if {@code formula} is {@code null}
* @since 1.1.2
*/
public static FormulaTerm formula(Formula formula) {
Objects.requireNonNull(formula, "formula cannot be null");
return new FormulaTerm(formula.getFormula());
}
/**
* Constructors for a {@link DQLTerm} in case you already have a prepared DQL query
*
* @param dql DQL
* @return dql term
*/
public static DQLTerm rawQuery(String dql) {
if (JNXStringUtil.isEmpty(dql)) {
throw new IllegalArgumentException("DQL query cannot be null");
}
return new DQLTerm() {
@Override
public String toString() {
return dql;
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy