"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.KQL_RANGE_OPERATOR_MAP = exports.KQL_FUNCTION_RANGE = void 0;
exports.buildNodeParams = buildNodeParams;
exports.isNode = isNode;
exports.toElasticsearchQuery = toElasticsearchQuery;
exports.toKqlExpression = toKqlExpression;
var _literal = require("../node_types/literal");
var _node_types = require("../node_types");
var ast = _interopRequireWildcard(require("../ast"));
var _filters = require("../../filters");
var _get_fields = require("./utils/get_fields");
var _utils = require("../../utils");
var _get_full_field_name_node = require("./utils/get_full_field_name_node");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

const KQL_FUNCTION_RANGE = 'range';
exports.KQL_FUNCTION_RANGE = KQL_FUNCTION_RANGE;
const KQL_RANGE_OPERATOR_MAP = {
  gt: '>',
  gte: '>=',
  lt: '<',
  lte: '<='
};
exports.KQL_RANGE_OPERATOR_MAP = KQL_RANGE_OPERATOR_MAP;
function isNode(node) {
  return node.function === KQL_FUNCTION_RANGE;
}
function buildNodeParams(fieldName, operator, value) {
  // Run through the parser instead treating it as a literal because it may contain wildcards
  const fieldNameArg = ast.fromLiteralExpression(fieldName);
  const valueArg = (0, _literal.buildNode)(value);
  return {
    arguments: [fieldNameArg, operator, valueArg]
  };
}
function toElasticsearchQuery(node, indexPattern, config = {}, context = {}) {
  const [fieldNameArg, operatorArg, valueArg] = node.arguments;
  const fullFieldNameArg = (0, _get_full_field_name_node.getFullFieldNameNode)(fieldNameArg, indexPattern, context !== null && context !== void 0 && context.nested ? context.nested.path : undefined);
  const fields = indexPattern ? (0, _get_fields.getFields)(fullFieldNameArg, indexPattern) : [];

  // If no fields are found in the index pattern we send through the given field name as-is. We do this to preserve
  // the behaviour of lucene on dashboards where there are panels based on different index patterns that have different
  // fields. If a user queries on a field that exists in one pattern but not the other, the index pattern without the
  // field should return no results. It's debatable whether this is desirable, but it's been that way forever, so we'll
  // keep things familiar for now.
  if (fields && fields.length === 0) {
    fields.push({
      name: ast.toElasticsearchQuery(fullFieldNameArg),
      scripted: false,
      type: ''
    });
  }
  const queries = fields.map(field => {
    const wrapWithNestedQuery = query => {
      // Wildcards can easily include nested and non-nested fields. There isn't a good way to let
      // users handle this themselves so we automatically add nested queries in this scenario.
      const subTypeNested = (0, _utils.getDataViewFieldSubtypeNested)(field);
      if (!_node_types.nodeTypes.wildcard.isNode(fullFieldNameArg) || !(subTypeNested !== null && subTypeNested !== void 0 && subTypeNested.nested) || context.nested) {
        return query;
      } else {
        return {
          nested: {
            path: subTypeNested.nested.path,
            query,
            score_mode: 'none',
            ...(typeof config.nestedIgnoreUnmapped === 'boolean' && {
              ignore_unmapped: config.nestedIgnoreUnmapped
            })
          }
        };
      }
    };
    const queryParams = {
      [operatorArg]: ast.toElasticsearchQuery(valueArg)
    };
    if (field.scripted) {
      return {
        script: (0, _filters.getRangeScript)(field, queryParams)
      };
    } else if (field.type === 'date') {
      const timeZoneParam = config.dateFormatTZ ? {
        time_zone: (0, _utils.getTimeZoneFromSettings)(config.dateFormatTZ)
      } : {};
      return wrapWithNestedQuery({
        range: {
          [field.name]: {
            ...queryParams,
            ...timeZoneParam
          }
        }
      });
    }
    return wrapWithNestedQuery({
      range: {
        [field.name]: queryParams
      }
    });
  });
  return {
    bool: {
      should: queries,
      minimum_should_match: 1
    }
  };
}
function toKqlExpression(node) {
  const [field, operator, value] = node.arguments;
  return `${ast.toKqlExpression(field)} ${KQL_RANGE_OPERATOR_MAP[operator]} ${ast.toKqlExpression(value)}`;
}