File

src/lib/service/search/search-query.model.ts

Description

The SearchQuery Class

See SearchService for Usage

Index

Properties
Methods

Constructor

constructor()

Properties

__updateCause
__updateCause: string
Type : string
Static BASE_PARAMS
BASE_PARAMS: object
Type : object
Default value : { TYPE: 'type', CREATOR: 'creator', CREATED: 'created', MODIFIER: 'modifier', MODIFIED: 'modified', FILESIZE: 'filesize', FILENAME: 'filename', MIMETYPEGROUP: 'mimetypegroup', FOLDER: 'folder' }

Base Parameters for a Search Query

Public contextFolderTypes
contextFolderTypes: ObjectType[]
Type : ObjectType[]
Default value : []

List of context folder types

Static DEFAULT_SEARCH_MODE
DEFAULT_SEARCH_MODE: string
Type : string
Default value : 'idxs'

Detault Search mode Index

Public expertMode
expertMode:
Default value : false

Whether or not the term is an expert mode query

Public fields
fields: string[]
Type : string[]

Array of fields to request from the search service, leaving this blank will return the fields specified in the result field configuration

Static FILE_SIZE_BUCKETS
FILE_SIZE_BUCKETS: object
Type : object
Default value : { NONE: 'none', LT1MB: 'lt1MB', LT10MB: 'lt10MB', LT100MB: 'lt100MB', GT100MB: 'gt100MB' }

filesize buckets property names

Public filters
filters: SearchFilter[]
Type : SearchFilter[]
Default value : []

List of filters to define the query

Static FULLTEXT_SEARCH_MODE
FULLTEXT_SEARCH_MODE: string
Type : string
Default value : 'fts'

Search mode for Full test Search

Public highlighting
highlighting: boolean
Type : boolean
Default value : false
Static MIMETYPEGROUP_BUCKETS
MIMETYPEGROUP_BUCKETS: object
Type : object
Default value : { PDF: 'pdf', MAIL: 'mail', WORD: 'word', IMAGE: 'image', OCTET_STREAM: 'octet-stream', TXT: 'txt', EXCEL: 'excel', POWERPOINT: 'powerpoint', VIDEO: 'video', HTML: 'html', AUDIO: 'audio', ZIP: 'zip' }

mimetype buckets property names

Public Optional name
name: string
Type : string
Static RELATIVE_DATE_BUCKETS
RELATIVE_DATE_BUCKETS: object
Type : object
Default value : { TODAY: 'today', YESTERDAY: 'yesterday', TOMORROW: 'tomorrow', THIS_WEEK: 'thisweek', LAST_WEEK: 'lastweek', NEXT_WEEK: 'nextweek', THIS_MONTH: 'thismonth', LAST_MONTH: 'lastmonth', NEXT_MONTH: 'nextmonth', THIS_QUARTER: 'thisquarter', LAST_QUARTER: 'lastquarter', NEXT_QUARTER: 'nextquarter', THIS_YEAR: 'thisyear', LAST_YEAR: 'lastyear', NEXT_YEAR: 'nextyear' }

Relative date buckets property names

Public resolveReference
resolveReference:
Default value : true

Resolve references with their title instead of their actual value

Public scope
scope: QueryScope
Type : QueryScope

The scope of the query

Public searchMode
searchMode: string
Type : string
Default value : SearchQuery.DEFAULT_SEARCH_MODE

The search mode to be used (SearchQuery.DEFAULT_SEARCH_MODE or SearchQuery.FULLTEXT_SEARCH_MODE)

Public sortOptions
sortOptions: SortOption[]
Type : SortOption[]
Default value : []

Additional options to be applied to the query

Public state
state: SearchState
Type : SearchState
Default value : new SearchState()

The state of the current query

Public suggest
suggest: boolean
Type : boolean

Whether or not to retrieve suggestions

Public term
term: string
Type : string

fulltext search term

Static TIME_PERIOD_BUCKETS
TIME_PERIOD_BUCKETS: object
Type : object
Default value : { TODAY: 'today', YESTERDAY: 'yesterday', THIS_WEEK: 'thisweek', LAST_WEEK: 'lastweek', THIS_MONTH: 'thismonth', LAST_MONTH: 'lastmonth', THIS_YEAR: 'thisyear', LAST_YEAR: 'lastyear' }

Time period buckets property names

Public types
types: ObjectType[]
Type : ObjectType[]
Default value : []

List of object types to be fetched by the query. Leaving this blank will return results from any type

Static UPDATE_CAUSE
UPDATE_CAUSE: object
Type : object
Default value : { TOGGLED_TYPE: 'cause.type.toggled', TOGGLED_EXPERTMODE: 'cause.expertmode.toggled', TERM_SET: 'cause.term.set', TYPES_SET: 'cause.types.set', CONTEXT_FOLDER_SET: 'cause.contextfolder.set', TOGGLED_FILTER: 'cause.filter.toggled', ADDED_FILTER: 'cause.filter.added', REMOVED_FILTER: 'cause.filter.removed', }
Public withContext
withContext: boolean
Type : boolean
Default value : false

Methods

Public addFilter
addFilter(filter: SearchFilter)

Adds a new filter to the query. If there already is a filter set for the given property, it will be overridden.

Parameters :
Name Type Optional Description
filter SearchFilter no

The filter to be added

Returns : void
Public addSortOption
addSortOption(name: string, order: string, missing?: string)

Adding new Sort Options Sort Options are only added if they are not already present

Parameters :
Name Type Optional
name string no
order string no
missing string yes
Returns : void
Public addType
addType(type: ObjectType)

Adds a new target type to the query

Parameters :
Name Type Optional Description
type ObjectType no

Object type to be added

Returns : void
Public getFilter
getFilter(propertyName: string)

Retrieves a filter by its property name.

Parameters :
Name Type Optional Description
propertyName string no

The filters property name (qname of form element)

Returns : SearchFilter

Search Filter Object

Public getQueryJson
getQueryJson(resolveReference?: boolean)

Generate a query JSON from the current SearchQuery that can be send to the search service.

Parameters :
Name Type Optional Description
resolveReference boolean yes

in case of csv export the resolving of references is set by configuration

Returns : any
Public getTableFilters
getTableFilters(propertyName: string)
Parameters :
Name Type Optional
propertyName string no
Returns : SearchFilter[]
Public removeFilter
removeFilter(filterPropertyName: string)

Removes a filter from the query.

Parameters :
Name Type Optional Description
filterPropertyName string no

The filter (its property name) to be removed

Returns : void
Public removeSortOption
removeSortOption(name: string)
Parameters :
Name Type Optional
name string no
Returns : void
Public removeType
removeType(type: ObjectType)

Removes a type from the target types list

Parameters :
Name Type Optional Description
type ObjectType no

The object type to be removed

Returns : void
Public toggleFilter
toggleFilter(filter: SearchFilter, override?: boolean)

Adds or removes the given filter based on the current settings

Parameters :
Name Type Optional Description
filter SearchFilter no

The filter to be toggled

override boolean yes
Returns : void
Public toggleType
toggleType(type: ObjectType)

Adds or removes the given type based on the current settings

Parameters :
Name Type Optional Description
type ObjectType no

The object type to be toggled

Returns : void
import {ObjectType} from '../../model/object-type.model';
import {DatePipe} from '@angular/common';

//export type QueryScope = 'indexdate' | 'content' | 'all';

export enum QueryScope {
  ALL = 'all',
  CONTENT = 'content',
  INDEX_DATA = 'indexdata'
}

/**
 * The SearchQuery Class
 *
 * See {@link SearchService} for Usage
 */
export class SearchQuery {
  /**
   * Base Parameters for a Search Query
   */
  public static BASE_PARAMS = {
    TYPE: 'type',
    CREATOR: 'creator',
    CREATED: 'created',
    MODIFIER: 'modifier',
    MODIFIED: 'modified',
    FILESIZE: 'filesize',
    FILENAME: 'filename',
    MIMETYPEGROUP: 'mimetypegroup',
    FOLDER: 'folder'
  };

  /**
   * Time period buckets property names
   */
  public static TIME_PERIOD_BUCKETS = {
    TODAY: 'today',
    YESTERDAY: 'yesterday',
    THIS_WEEK: 'thisweek',
    LAST_WEEK: 'lastweek',
    THIS_MONTH: 'thismonth',
    LAST_MONTH: 'lastmonth',
    THIS_YEAR: 'thisyear',
    LAST_YEAR: 'lastyear'
  };

  /**
 * Relative date buckets property names
 */
  public static RELATIVE_DATE_BUCKETS = {
    TODAY: 'today',
    YESTERDAY: 'yesterday',
    TOMORROW: 'tomorrow',
    THIS_WEEK: 'thisweek',
    LAST_WEEK: 'lastweek',
    NEXT_WEEK: 'nextweek',
    THIS_MONTH: 'thismonth',
    LAST_MONTH: 'lastmonth',
    NEXT_MONTH: 'nextmonth',
    THIS_QUARTER: 'thisquarter',
    LAST_QUARTER: 'lastquarter',
    NEXT_QUARTER: 'nextquarter',
    THIS_YEAR: 'thisyear',
    LAST_YEAR: 'lastyear',
    NEXT_YEAR: 'nextyear'
  };


  /**
   * mimetype buckets property names
   */
  public static MIMETYPEGROUP_BUCKETS = {
    PDF: 'pdf',
    MAIL: 'mail',
    WORD: 'word',
    IMAGE: 'image',
    OCTET_STREAM: 'octet-stream',
    TXT: 'txt',
    EXCEL: 'excel',
    POWERPOINT: 'powerpoint',
    VIDEO: 'video',
    HTML: 'html',
    AUDIO: 'audio',
    ZIP: 'zip'
  };

  /**
   * filesize buckets property names
   */
  public static FILE_SIZE_BUCKETS = {
    NONE: 'none',
    LT1MB: 'lt1MB',
    LT10MB: 'lt10MB',
    LT100MB: 'lt100MB',
    GT100MB: 'gt100MB'
  };

  // list of things that may have changed the current query
  public static UPDATE_CAUSE = {
    TOGGLED_TYPE: 'cause.type.toggled',
    TOGGLED_EXPERTMODE: 'cause.expertmode.toggled',
    TERM_SET: 'cause.term.set',
    TYPES_SET: 'cause.types.set',
    CONTEXT_FOLDER_SET: 'cause.contextfolder.set',
    TOGGLED_FILTER: 'cause.filter.toggled',
    ADDED_FILTER: 'cause.filter.added',
    REMOVED_FILTER: 'cause.filter.removed',
  };
  /**
   * Detault Search mode Index
   */
  public static DEFAULT_SEARCH_MODE = 'idxs';
  /**
   * Search mode for Full test Search
   */
  public static FULLTEXT_SEARCH_MODE = 'fts';
  /**
   * fulltext search term
   */
  public term: string;
  /**
   * Array of fields to request from the search service, leaving this blank will return the fields specified in the result field configuration
   */
  public fields: string[];
  /**
   * List of object types to be fetched by the query. Leaving this blank will return results from any type
   */
  public types: ObjectType[] = [];
  /**
   * List of context folder types
   */
  public contextFolderTypes: ObjectType[] = [];
  /**
   * List of filters to define the query
   */
  public filters: SearchFilter[] = [];
  /**
   * Whether or not to retrieve suggestions
   */
  public suggest: boolean;
  /**
   * Whether or not the term is an expert mode query
   */
  public expertMode = false;
  /**
   * The scope of the query
   */
  public scope: QueryScope;
  /**
   * The search mode to be used (SearchQuery.DEFAULT_SEARCH_MODE or SearchQuery.FULLTEXT_SEARCH_MODE)
   */
  public searchMode: string = SearchQuery.DEFAULT_SEARCH_MODE;
  /**
   * Additional options to be applied to the query
   */
  public sortOptions: SortOption[] = [];
  /**
   * Resolve references with their title instead of their actual value
   */
  public resolveReference = true;
  /**
   * The state of the current query
   */
  public state: SearchState = new SearchState();

  public highlighting: boolean = false;
  public withContext: boolean = false;

  public name?: string;

  // Indicator what caused the update of a SearchQuery object.
  // Usefull for components that subscribed to a query, and need to
  // track the kind of changes made
  __updateCause: string;

  constructor() {}

  /**
   * Adds a new target type to the query
   *
   * @param type Object type to be added
   */
  public addType(type: ObjectType) {
    if (!this.types.find(t => t.id === type.id)) {
      this.types.push(type);
    }
  }

  /**
   * Removes a type from the target types list
   *
   * @param type The object type to be removed
   */
  public removeType(type: ObjectType) {
    this.types = this.types.filter(t => t.id !== type.id);
  }

  /**
   * Adds or removes the given type based on the current settings
   *
   * @param type The object type to be toggled
   */
  public toggleType(type: ObjectType) {
    if (this.types.find(t => t.id === type.id)) {
      this.removeType(type);
    } else {
      this.types.push(type);
    }
  }

  /**
   * Adds a new filter to the query. If there already is a filter set for the given property, it will be overridden.
   *
   * @param filter The filter to be added
   */
  public addFilter(filter: SearchFilter) {
    if (!filter) {
      return;
    }
    if (!this.getFilter(filter.property)) {
      this.filters.push(filter);
    } else {
      // if there already is a filter set for the target property
      // we'll just override it with the new value
      this.removeFilter(filter.property);
      this.filters.push(filter);
    }
  }

  /**
   * Removes a filter from the query.
   *
   * @param filterPropertyName The filter (its property name) to be removed
   */
  public removeFilter(filterPropertyName: string) {
    this.filters = this.filters.filter(f => f.property !== filterPropertyName);
  }

  /**
   * Adds or removes the given filter based on the current settings
   *
   * @param filter The filter to be toggled
   */
  public toggleFilter(filter: SearchFilter, override?: boolean) {
    if (this.getFilter(filter.property)) {
      this.removeFilter(filter.property);
      if (override) {
        this.filters.push(filter);
      }
    } else {
      this.filters.push(filter);
    }
  }

  /**
   * Retrieves a filter by its property name.
   *
   * @param propertyName The filters property name (qname of form element)
   * @returns Search Filter Object
   */
  public getFilter(propertyName: string): SearchFilter {
    return this.filters.find(f => f.property === propertyName);
  }

  public getTableFilters(propertyName: string): SearchFilter[] {
    return this.filters.filter(f => f.property.startsWith(propertyName + '.'));
  }

  /**
   * Adding new Sort Options
   * Sort Options are only added if they are not already present
   *
   * @param name
   * @param order
   * @param missing
   */
  public addSortOption(name: string, order: string, missing?: string) {
    if (!this.sortOptions.find(s => s.field === name)) {
      this.sortOptions.push(new SortOption(name, order, missing));
    }
  }

  /**
   *
   * @param name
   */
  public removeSortOption(name: string) {
    this.sortOptions = this.sortOptions.filter(s => s.field !== name);
  }

  /**
   * Generate a query JSON from the current SearchQuery that can be send to the search service.
   *
   * @param resolveReference in case of csv export the resolving of references is set by configuration
   */
  public getQueryJson(resolveReference?: boolean) {
    // Convert the current query object to a query JSON that can be consumed by the search service backend.
    // To keep it short, we'll only add properties that are set and differ from default values
    const queryJson: any = {};

    // add type filters
    if (this.types.length > 0) {
      queryJson.types = this.types.map(t =>
        typeof t === 'string' ? t : t.name
      );
    }

    // add context folder type filters
    if (this.contextFolderTypes.length > 0) {
      queryJson.contextfoldertypes = this.contextFolderTypes.map(t => t.name);
    }

    // filters
    if (this.filters.length > 0) {
      queryJson.filters = {};
      this.filters.forEach(f => {
        queryJson.filters[f.property] = f.toQuery();
      });
    }
    if (this.term) {
      queryJson.term = this.term;
    }
    // search fields
    if (this.fields) {
      queryJson.fields = this.fields;
    }
    if (this.name) {
      queryJson.name = this.name;
    }
    // add options when they differ from the default values
    if (this.applyOptions()) {
      queryJson.options = {};
      queryJson.options.scope = this.scope;
      if (this.suggest) {
        queryJson.options.suggest = true;
      }
      if (this.expertMode) {
        queryJson.options.expertmode = true;
      }

      queryJson.options.resolvereference = resolveReference !== undefined ? resolveReference : true;

      if (this.searchMode !== SearchQuery.DEFAULT_SEARCH_MODE) {
        queryJson.options.searchmode = this.searchMode;
      }
      if (this.sortOptions && this.sortOptions.length) {
        queryJson.options.sort = {};
        this.sortOptions.forEach((sortOption: SortOption) => {
          if (sortOption.order) {
            queryJson.options.sort[sortOption.field] = {
              order: sortOption.order
            };
          }
        });
      }

      if (this.highlighting) {
        queryJson.options.highlighting = this.highlighting;
      }
      if (this.withContext) {
        queryJson.options.withcontext = this.withContext;
      }
    }
    return queryJson;
  }

  // determines whether or not the query send to the search service should contain options
  private applyOptions(): boolean {
    return (
      this.expertMode ||
      !!this.scope ||
      this.suggest ||
      this.highlighting ||
      this.resolveReference ||
      this.withContext ||
      this.searchMode !== SearchQuery.DEFAULT_SEARCH_MODE ||
      this.sortOptions.length > 0
    );
  }
}

/**
 * @ignore
 * Creates the Model of Sort Options
 */
export class SortOption {
  constructor(
    public field: string,
    public order: string,
    public missing?: string
  ) {}
}

/**
 * @ignore
 * Creates the Model of Field Definitions
 */
export class FieldDefinition {
  constructor(
    public elements: any[] = [],
    public sortorder: any[] = [],
    public grouporder: any[] = [],
    public pinned: any[] = [],
    public alignmentx: {qname: string, value: string}[] = [],
    public mode?: string
  ) {}
}

/**
 * @ignore
 * Class representing the state of a query
 */
export class SearchState {
  public count: {value: number, relation?: string};
  public aggregations;
  public lastChange?: string;

  /**
   * @ignore
   */
  constructor() {
    this.aggregations = {
      type: new Map<string, number>(),
      contextType: new Map<string, number>(),
      created: [],
      modified: [],
      mimetypegroup: [],
      filesize: []
    };
  }

  get totalCount() {
    return Array.from(this.aggregations.type.values()).reduce((acc: number, cur: number) => acc + cur, 0) as number;
  }

  get isEmpty() {
    return !(this.count && this.count.value);
  }

  addAggregations(type: string, key: string, value: number, agg?) {
    switch (type) {
      case 'contexttype': {
        this.aggregations.contextType.set(key, value);
        break;
      }
      case SearchQuery.BASE_PARAMS.TYPE: {
        this.aggregations.type.set(key, value);
        break;
      }
      case SearchQuery.BASE_PARAMS.CREATED: {
        this.aggregations.created.push({
          key: key,
          value: value
        });
        break;
      }
      case SearchQuery.BASE_PARAMS.MODIFIED: {
        this.aggregations.modified.push({
          key: key,
          value: value
        });
        break;
      }
      case SearchQuery.BASE_PARAMS.MIMETYPEGROUP: {
        this.aggregations.mimetypegroup.push({
          key: key,
          value: value
        });
        break;
      }
      case SearchQuery.BASE_PARAMS.FILESIZE: {
        this.aggregations.filesize.push({
          key: key,
          value: value,
          from: agg.from,
          to: agg.to || Infinity,
          label: key.replace('gt', '> ').replace('lt', '< ')
        });
        break;
      }
    }
  }
}

/**
 * @ignore
 * Creates the Model of Search Results
 */
export class SearchResult {
  public count: {value: number, relation?: string};
  public suggests: string[];
  public hits: any[];
  public typeName: string;
  public fields: FieldDefinition;

  constructor() {}
}

export class SearchFilter {
  /**
   * available operators for a search filter
   */
  public static OPERATOR = {
    /** equal */
    EQUAL: 'eq',
    /** match (for string with classification "path6666") */
    MATCH: 'match',
    /** match at least one of the provided values (value has to be an array)  */
    IN: 'in',
    /** greater than */
    GREATER_THAN: 'gt',
    /** greater than or equal */
    GREATER_OR_EQUAL: 'gte', //
    LESS_THAN: 'lt', // less than
    LESS_OR_EQUAL: 'lte', // less than or equal
    INTERVAL: 'gtlt', // interval
    INTERVAL_INCLUDE_BOTH: 'gtelte', // interval include left and right
    INTERVAL_INCLUDE_TO: 'gtlte', // interval include right
    INTERVAL_INCLUDE_FROM: 'gtelt', // interval include left
    RANGE: 'rg', // aggegation ranges
    MORE: 'mr',
    USE_NOT: 'usenot'
  };

  /**
   * Constructor for creating a new SearchFilter.
   *
   * @param property The qualified name of the field this filter should apply to.
   * @param operator Operator indicating how to handle the filters value(s). See SearchFilter.OPERATOR for available operators.
   * @param firstValue The filters value
   * @param secondValue Optional second value for filters that for example define ranges of values
   * @param transformDate Flag to transform date hours and minutes based on operator
   */
  constructor(
    public property: string,
    public operator: string,
    public firstValue: any,
    public secondValue?: any,
    public transformDate?: {time?: boolean; timezone?: boolean},
    public useNot?: boolean,
    public actualOperator?: string
  ) { }

  formatDate(value: any) {
    return this.transformDate && value
      ? this.transformDate.timezone
        ? new DatePipe('en').transform(value, 'yyyy-MM-ddTZ')
        : this.transformDate.time
          ? new Date(value).toISOString().slice(0, 16) + 'Z'
          : new DatePipe('en').transform(value, 'yyyy-MM-dd')
      : value;
  }

  toQuery() {
    const v1 = this.operator === 'mr' ? this.firstValue : this.formatDate(this.firstValue);
    const o = this.operator === 'mr' ? 'rg' : (this.useNot ? this.actualOperator : this.operator);
    return {
      o,
      v1,
      ...(this.secondValue && {v2: this.formatDate(this.secondValue)}),
      ...(this.useNot && { usenot: true, actualOperator: this.actualOperator })
    };
  }

  toDateTimeQuery() {
    if (this.transformDate && this.transformDate.timezone && this.firstValue) {
      let firstValue = this.firstValue;
      let secondValue = this.secondValue;
      const endDate = new Date(secondValue || firstValue);
      endDate.setHours(23, 59, 59, 999);
      if (this.operator === SearchFilter.OPERATOR.LESS_OR_EQUAL) {
        firstValue = endDate.toISOString();
      } else {
        const startDate = new Date(firstValue);
        if (
          this.operator === SearchFilter.OPERATOR.GREATER_THAN ||
          this.operator === SearchFilter.OPERATOR.INTERVAL
        ) {
          startDate.setHours(23, 59, 59, 999);
        } else {
          startDate.setHours(0, 0, 0, 0);
        }
        firstValue = startDate.toISOString();
      }
      if (
        this.operator === SearchFilter.OPERATOR.INTERVAL_INCLUDE_BOTH ||
        this.operator === SearchFilter.OPERATOR.EQUAL
      ) {
        secondValue = endDate.toISOString();
      }
      return {
        o:
          this.operator === SearchFilter.OPERATOR.EQUAL
            ? SearchFilter.OPERATOR.INTERVAL_INCLUDE_BOTH
            : this.operator,
        v1: firstValue,
        ...(secondValue && {v2: secondValue})
      };
    } else {
      return this.toQuery();
    }
  }

  /**
   * @ignore
   */
  match(
    property: string,
    operator: string,
    firstValue: any,
    secondValue?: any
  ) {
    return (
      this.property === property &&
      this.operator === operator &&
      this.secondValue === secondValue &&
      (this.firstValue instanceof Array
        ? !!this.firstValue.find(v => v === firstValue)
        : this.firstValue === firstValue)
    );
  }
}

results matching ""

    No results matching ""