All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hcl.domino.data.CollectionSearchQuery Maven / Gradle / Ivy

There is a newer version: 1.44.0
Show newest version
/*
 * ==========================================================================
 * 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.data;

import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;

import com.hcl.domino.data.CollectionEntry.SpecialValue;
import com.hcl.domino.data.Database.Action;
import com.hcl.domino.dql.DQL.DQLTerm;
import com.hcl.domino.misc.Loop;

public interface CollectionSearchQuery extends SearchQuery {

  // decide where to start navigating the view

  public static class AllCollapsedEntries extends ExpandedEntries {

    public AllCollapsedEntries() {
      super(ExpandMode.AllCollapsed);
    }

    public AllCollapsedEntries expand(final DQLTerm dql) {
      if (this.getMode() == ExpandMode.AllCollapsed) {
        this.getDQLQueries().add(dql);
      }

      return this;
    }

    public AllCollapsedEntries expand(final int... noteIds) {
      if (this.getMode() == ExpandMode.AllCollapsed) {
        if (noteIds != null) {
          if (noteIds.length == 1) {
            this.getNoteIds().add(noteIds[0]);
          } else {
            final Collection noteIdsAsList = new ArrayList<>(noteIds.length);
            for (final int noteId : noteIds) {
              noteIdsAsList.add(noteId);
            }
            this.getNoteIds().addAll(noteIdsAsList);
          }
        }
      }

      return this;
    }

    public AllCollapsedEntries expand(final Set noteIds) {
      if (this.getMode() == ExpandMode.AllCollapsed) {
        this.getNoteIds().addAll(noteIds);
      }

      return this;
    }

    public AllCollapsedEntries expand(final String ftQuery) {
      if (this.getMode() == ExpandMode.AllCollapsed) {
        this.getFTQueries().add(ftQuery);
      }

      return this;
    }

  }

  public static class AllDeselectedEntries extends SelectedEntries {

    public AllDeselectedEntries() {
      super(SelectMode.AllDeselected);
    }

    public AllDeselectedEntries select(final DQLTerm dql) {
      if (this.getMode() == SelectMode.AllDeselected) {
        this.getDQLQueries().add(dql);
      }

      return this;
    }

    public AllDeselectedEntries select(final int... noteIds) {
      if (this.getMode() == SelectMode.AllDeselected) {
        if (noteIds != null) {
          if (noteIds.length == 1) {
            this.getNoteIds().add(noteIds[0]);
          } else {
            final Collection noteIdsAsList = new ArrayList<>(noteIds.length);
            for (final int noteId : noteIds) {
              noteIdsAsList.add(noteId);
            }
            this.getNoteIds().addAll(noteIdsAsList);
          }
        }
      }

      return this;
    }

    public AllDeselectedEntries select(final Set noteIds) {
      if (this.getMode() == SelectMode.AllDeselected) {
        this.getNoteIds().addAll(noteIds);
      }

      return this;
    }

    public AllDeselectedEntries select(final String ftQuery) {
      if (this.getMode() == SelectMode.AllDeselected) {
        this.getFTQueries().add(ftQuery);
      }

      return this;
    }

    /**
     * Selects collection entries via key lookup
     *
     * @param key   lookup key
     * @param exact true for exact match, false for prefix search
     * @return this search query
     */
    public AllDeselectedEntries selectByKey(final List key, final boolean exact) {
      this.getLookupKeysMultiCol().add(new MultiColumnLookupKey(key, exact));

      return this;
    }

    /**
     * Selects collection entries via key lookup
     *
     * @param key   lookup key
     * @param exact true for exact match, false for prefix search
     * @return this search query
     */
    public AllDeselectedEntries selectByKey(final String key, final boolean exact) {
      this.getLookupKeysSingleCol().add(new SingleColumnLookupKey(key, exact));

      return this;
    }
  }

  public static class AllExpandedEntries extends ExpandedEntries {

    public AllExpandedEntries() {
      super(ExpandMode.AllExpanded);
    }

    public AllExpandedEntries collapse(final int... noteIds) {
      if (this.getMode() == ExpandMode.AllExpanded) {
        if (noteIds != null) {
          if (noteIds.length == 1) {
            this.getNoteIds().add(noteIds[0]);
          } else {
            final Collection noteIdsAsList = new ArrayList<>(noteIds.length);
            for (final int noteId : noteIds) {
              noteIdsAsList.add(noteId);
            }
            this.getNoteIds().addAll(noteIdsAsList);
          }
        }
      }

      return this;
    }

    public AllExpandedEntries collapse(final Set noteIds) {
      if (this.getMode() == ExpandMode.AllExpanded) {
        this.getNoteIds().addAll(noteIds);
      }

      return this;
    }

    public AllExpandedEntries unselect(final DQLTerm dql) {
      if (this.getMode() == ExpandMode.AllExpanded) {
        this.getDQLQueries().add(dql);
      }

      return this;
    }

    public AllExpandedEntries unselect(final String ftQuery) {
      if (this.getMode() == ExpandMode.AllExpanded) {
        this.getFTQueries().add(ftQuery);
      }

      return this;
    }

  }

  public static class AllSelectedEntries extends SelectedEntries {

    public AllSelectedEntries() {
      super(SelectMode.AllSelected);
    }

    public AllSelectedEntries deselect(final DQLTerm dql) {
      if (this.getMode() == SelectMode.AllSelected) {
        this.getDQLQueries().add(dql);
      }

      return this;
    }

    public AllSelectedEntries deselect(final int... noteIds) {
      if (this.getMode() == SelectMode.AllSelected) {
        if (noteIds != null) {
          if (noteIds.length == 1) {
            this.getNoteIds().add(noteIds[0]);
          } else {
            final Collection noteIdsAsList = new ArrayList<>(noteIds.length);
            for (final int noteId : noteIds) {
              noteIdsAsList.add(noteId);
            }
            this.getNoteIds().addAll(noteIdsAsList);
          }
        }
      }

      return this;
    }

    public AllSelectedEntries deselect(final Set noteIds) {
      if (this.getMode() == SelectMode.AllSelected) {
        this.getNoteIds().addAll(noteIds);
      }

      return this;
    }

    public AllSelectedEntries deselect(final String ftQuery) {
      if (this.getMode() == SelectMode.AllSelected) {
        this.getFTQueries().add(ftQuery);
      }

      return this;
    }

    /**
     * Deselects collection entries via key lookup
     *
     * @param key   lookup key
     * @param exact true for exact match, false for prefix search
     * @return this search query
     */
    public AllSelectedEntries deselectByKey(final List key, final boolean exact) {
      this.getLookupKeysMultiCol().add(new MultiColumnLookupKey(key, exact));

      return this;
    }

    /**
     * Deselects collection entries via key lookup
     *
     * @param key   lookup key
     * @param exact true for exact match, false for prefix search
     * @return this search query
     */
    public AllSelectedEntries deselectByKey(final String key, final boolean exact) {
      this.getLookupKeysSingleCol().add(new SingleColumnLookupKey(key, exact));

      return this;
    }
  }

  /**
   * @since 1.0.18
   */
  @FunctionalInterface
  public interface BasicCollectionEntryProcessor {
    /**
     * Method is called for each read collection entry
     *
     * @param entry the read entry
     * @return action whether to continue or stop reading
     */
    Action entryRead(CollectionEntry entry);
  }

  /**
   * Builder interface that takes the collection entries and
   * produces a result.
   *
   * @param  type of computation result
   */
  public interface CollectionEntryProcessor {

    /**
     * This method is called when view reading is done. Add code
     * here to post process your lookup result.
     *
     * @param result lookup result
     * @return processed result
     */
    T end(T result);

    /**
     * Method is called for each read collection entry
     *
     * @param result result object to add the entry data
     * @param entry  entry
     * @return action whether to continue or stop reading
     */
    Action entryRead(T result, CollectionEntry entry);

    /**
     * This method is called when we start reading collection entries.
*
* Since the view index might change while reading entries, we might * need to restart reading from the beginning. * * @return an object to be passed to {@link #entryRead(Object, CollectionEntry)} * for each read entry */ T start(); } // configure expanded and selected navigation, e.g. next selected, next // expanded, next selected expanded public abstract static class ExpandedEntries { public static AllCollapsedEntries collapseAll() { return new AllCollapsedEntries(); } public static AllExpandedEntries expandAll() { return new AllExpandedEntries(); } private final ExpandMode m_mode; private final Set m_noteIds; private final List m_dqlQueries; private final List m_ftQueries; private ExpandedEntries(final ExpandMode mode) { this.m_mode = mode; this.m_noteIds = new HashSet<>(); this.m_dqlQueries = new ArrayList<>(); this.m_ftQueries = new ArrayList<>(); } public List getDQLQueries() { return this.m_dqlQueries; } public List getFTQueries() { return this.m_ftQueries; } public ExpandMode getMode() { return this.m_mode; } public Set getNoteIds() { return this.m_noteIds; } } public enum ExpandMode { AllExpanded, AllCollapsed } public static class MultiColumnLookupKey { private final List m_key; private final boolean m_exact; public MultiColumnLookupKey(final List key, final boolean exact) { this.m_key = key; this.m_exact = exact; } public List getKey() { return this.m_key; } public boolean isExact() { return this.m_exact; } } public abstract static class SelectedEntries { public static AllDeselectedEntries deselectAll() { return new AllDeselectedEntries(); } public static AllSelectedEntries selectAll() { return new AllSelectedEntries(); } private final SelectMode m_mode; private final Set m_noteIds; private final List m_dqlQueries; private final List m_ftQueries; private final List m_lookupKeysSingleCol; private final List m_lookupKeysMultiCol; private SelectedEntries(final SelectMode mode) { this.m_mode = mode; this.m_noteIds = new HashSet<>(); this.m_dqlQueries = new ArrayList<>(); this.m_ftQueries = new ArrayList<>(); this.m_lookupKeysSingleCol = new ArrayList<>(); this.m_lookupKeysMultiCol = new ArrayList<>(); } public List getDQLQueries() { return this.m_dqlQueries; } public List getFTQueries() { return this.m_ftQueries; } public List getLookupKeysMultiCol() { return this.m_lookupKeysMultiCol; } public List getLookupKeysSingleCol() { return this.m_lookupKeysSingleCol; } public SelectMode getMode() { return this.m_mode; } public Set getNoteIds() { return this.m_noteIds; } } public enum SelectMode { AllSelected, AllDeselected } public static class SingleColumnLookupKey { private final String m_key; private final boolean m_exact; public SingleColumnLookupKey(final String key, final boolean exact) { this.m_key = key; this.m_exact = exact; } public String getKey() { return this.m_key; } public boolean isExact() { return this.m_exact; } } // decide how entries are read /** * Build a result out of the collection entries * * @param result type * @param skip paging offset * @param count paging count * @param processor builder code to produce the result * @return result */ T build(int skip, int count, CollectionEntryProcessor processor); /** * Collect all {@link CollectionEntry} objects as list * * @param skip paging offset * @param count paging count * @return list of collection entries */ List collectEntries(int skip, int count); /** * Collect all {@link CollectionEntry} objects in a {@link Collection} * * @param skip the number of entries to skip when collecting * @param count the maximum number of entries to collect * @param collection collection to add entries */ void collectEntries(int skip, int count, Collection collection); // methods to control reading expanded entries in categorized views /** * Return the note ids of the search result as an ordered {@link Set}. *

* Implementations are likely, but not guaranteed, to return a * {@link LinkedHashSet}. *

* * @param skip paging offset * @param count paging count * @return set of note ids */ Set collectIds(int skip, int count); /** * Adds all note ids of the search result to a note ID collection, with special * support for {@link IDTable} * * @param skip paging offset * @param count paging count * @param idTable note ID collection */ void collectIds(int skip, int count, Collection idTable); // decide what to do with the view content /** * Convenience method that calls {@link #select(SelectedEntries)} with * {@link SelectedEntries#deselectAll()} and * {@link AllDeselectedEntries#selectByKey(List, boolean)}. * * @param key lookup key * @param exact true for exact match, false for prefix search * @return this search query */ CollectionSearchQuery deselectByKey(List key, boolean exact); /** * Convenience method that calls {@link #select(SelectedEntries)} with * {@link SelectedEntries#selectAll()} and * {@link AllSelectedEntries#deselectByKey(String, boolean)}. * * @param key lookup key * @param exact true for exact match, false for prefix search * @return this search query */ CollectionSearchQuery deselectByKey(String key, boolean exact); /** * Direction and read mode * * @param mode mode * @return this search query */ CollectionSearchQuery direction(Navigate mode); /** * Configure which elements are expanded * * @param expandedEntries use {@link ExpandedEntries#expandAll()} or * {@link ExpandedEntries#collapseAll()} to start * building this object * @return this search query */ CollectionSearchQuery expand(ExpandedEntries expandedEntries); /** * Returns the first {@link CollectionEntry} * * @return an {@code Optional} describing the first entry, * or an empty {@code Optional} if there are no * matched entries */ default Optional firstEntry() { final List entries = this.collectEntries(0, 1); return Optional.ofNullable(entries.isEmpty() ? null : entries.get(0)); } /** * Returns the first {@link CollectionEntry} * * @return an {@code Optional} describing the first entry's note ID, * or an empty {@code Optional} if there are no * matched entries */ default Optional firstId() { final Set entries = this.collectIds(0, 1); return Optional.ofNullable(entries.isEmpty() ? null : entries.iterator().next()); } /** * Iterates through all selected entries and performs an action on each. *

* This is equivalent to calling * {@link #build(int, int, CollectionEntryProcessor)} with * a processor that performs no action on start/end and returns no value. *

* * @param processor the processor to execute on each entry * @since 1.0.18 */ default void forEach(final BasicCollectionEntryProcessor processor) { this.build(0, Integer.MAX_VALUE, new CollectionEntryProcessor() { @Override public Void end(final Void result) { return null; } @Override public Action entryRead(final Void result, final CollectionEntry entry) { processor.entryRead(entry); return null; } @Override public Void start() { return null; } }); } void forEachDocument(int skip, int count, BiConsumer consumer); /** * Decodes the collection column values, they can be read via * {@link CollectionEntry#get(String, Class, Object)} or * {@link CollectionEntry#getAsList(String, Class, List)}. * * @return this search query */ CollectionSearchQuery readColumnValues(); // which data should be read from the view index or from the document summary // data /** * Reads the document class for each view entry. * * @return this search query * @since 1.0.18 */ CollectionSearchQuery readDocumentClass(); /** * Read additional meta data for the collection entries or their document * * @param values special values * @return this search query */ CollectionSearchQuery readSpecialValues(Collection values); /** * Read additional meta data for the collection entries or their document * * @param values special values * @return this search query */ CollectionSearchQuery readSpecialValues(SpecialValue... values); /** * Reads the UNID of each collection entry. * * @return this search query */ CollectionSearchQuery readUNID(); /** * Configure which elements are selected * * @param selectedEntries use {@link SelectedEntries#selectAll()} or * {@link SelectedEntries#deselectAll()} to start * building this object * @return this search query */ CollectionSearchQuery select(SelectedEntries selectedEntries); /** * Convenience method that calls {@link #select(SelectedEntries)} with * {@link SelectedEntries#selectAll()} and * {@link AllSelectedEntries#deselectByKey(List, boolean)}. * * @param key lookup key * @param exact true for exact match, false for prefix search * @return this search query */ CollectionSearchQuery selectByKey(List key, boolean exact); /** * Convenience method that calls {@link #select(SelectedEntries)} with * {@link SelectedEntries#deselectAll()} and * {@link AllDeselectedEntries#selectByKey(String, boolean)}. * * @param key lookup key * @param exact true for exact match, false for prefix search * @return this search query */ CollectionSearchQuery selectByKey(String key, boolean exact); /** * Slow method to compute the total number of collection entries * * @return total */ int size(); /** * Restricts search result to a single category * * @param categoryLevels different levels of category values, supports strings * and {@link TemporalAccessor} objects * @return this search query */ CollectionSearchQuery startAtCategory(List categoryLevels); /** * Restrict search result to a single category * * @param category category, use "\" for multiple category levels * @return this search query */ CollectionSearchQuery startAtCategory(String category); /** * Start reading view data at an entry with the specified note id * * @param noteId note id * @return this search query */ CollectionSearchQuery startAtEntryId(int noteId); /** * Start reading view data at first entry * * @return this search query */ CollectionSearchQuery startAtFirstEntry(); /** * Start reading at last view row * * @return this search query */ CollectionSearchQuery startAtLastEntry(); /** * Start reading at a fixed collection position. Please note that this * position is not a unique identifier for entries, it may change * over time when the view index changes. * * @param pos position string, e.g. "1.2.1" * @return this search query */ CollectionSearchQuery startAtPosition(String pos); }