From f39016530d468243b8386c0b2dfede43d03d4d3a Mon Sep 17 00:00:00 2001 From: delvedor Date: Wed, 2 Sep 2020 16:27:01 +0200 Subject: [PATCH] Updated test --- test/dsl/aggregation-helpers.test.ts | 1678 ++++++++++++++++++++++++++ test/dsl/bool-optimize.test.ts | 777 ++++++++++++ test/dsl/boolean-and-helpers.test.ts | 350 ++++++ test/dsl/boolean-not-helpers.test.ts | 171 +++ test/dsl/boolean-or-helpers.test.ts | 334 +++++ test/dsl/query-helpers.test.ts | 792 ++++++++++++ 6 files changed, 4102 insertions(+) create mode 100644 test/dsl/aggregation-helpers.test.ts create mode 100644 test/dsl/bool-optimize.test.ts create mode 100644 test/dsl/boolean-and-helpers.test.ts create mode 100644 test/dsl/boolean-not-helpers.test.ts create mode 100644 test/dsl/boolean-or-helpers.test.ts create mode 100644 test/dsl/query-helpers.test.ts diff --git a/test/dsl/aggregation-helpers.test.ts b/test/dsl/aggregation-helpers.test.ts new file mode 100644 index 000000000..71f7f9ace --- /dev/null +++ b/test/dsl/aggregation-helpers.test.ts @@ -0,0 +1,1678 @@ +'use strict' + +import { test } from 'tap' +import { A } from '../../dsl' + +const shorthandError = new Error('This method does not support shorthand options') + +test('A is a function that generates the final aggs object', t => { + t.type(A, 'function') + + t.test('Basic', t => { + t.deepEqual(A({ a: 1 }, { b: 2 }, { c: 3 }), { + aggs: { + a: 1, + b: 2, + c: 3 + } + }) + t.end() + }) + + t.test('Should discard falsy values', t => { + t.deepEqual(A({ a: 1 }, false, { b: 2 }, null, { c: 3 }), { + aggs: { + a: 1, + b: 2, + c: 3 + } + }) + t.end() + }) + + t.end() +}) + +test('A.aggs is a method to add nested aggregations', t => { + t.test('Plain agg', t => { + const main = A.main.terms('foo') + + t.deepEqual(main, { + main: { terms: { field: 'foo' } } + }) + + const agg1 = A.sumAgg.sum('bar') + const agg2 = A.avgAgg.avg('baz') + + A.main.aggs(main, agg1, agg2) + + t.deepEqual(main, { + main: { + terms: { field: 'foo' }, + aggs: { + sumAgg: { sum: { field: 'bar' } }, + avgAgg: { avg: { field: 'baz' } } + } + } + }) + + t.end() + }) + + t.test('Already nested agg', t => { + const main = A.main.terms('foo', A.statsAgg.stats('faz')) + + t.deepEqual(main, { + main: { + terms: { field: 'foo' }, + aggs: { + statsAgg: { stats: { field: 'faz' } } + } + } + }) + + const agg1 = A.sumAgg.sum('bar') + const agg2 = A.avgAgg.avg('baz') + + A.main.aggs(main, agg1, agg2) + + t.deepEqual(main, { + main: { + terms: { field: 'foo' }, + aggs: { + statsAgg: { stats: { field: 'faz' } }, + sumAgg: { sum: { field: 'bar' } }, + avgAgg: { avg: { field: 'baz' } } + } + } + }) + + t.end() + }) + + t.test('Should filter falsy aggs', t => { + const main = A.main.terms('foo') + + t.deepEqual(main, { + main: { terms: { field: 'foo' } } + }) + + const agg1 = A.sumAgg.sum('bar') + const agg2 = A.avgAgg.avg('baz') + + A.main.aggs(main, agg1, null, agg2, false) + + t.deepEqual(main, { + main: { + terms: { field: 'foo' }, + aggs: { + sumAgg: { sum: { field: 'bar' } }, + avgAgg: { avg: { field: 'baz' } } + } + } + }) + + t.end() + }) + + t.end() +}) + +test('avg', t => { + t.deepEqual(A.aggName.avg({ field: 'foo' }), { + aggName: { + avg: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.avg('foo'), { + aggName: { + avg: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('weightedAvg', t => { + t.deepEqual(A.aggName.weightedAvg({ field: 'foo' }), { + aggName: { + weighted_avg: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.weightedAvg('foo'), + shorthandError + ) + + t.end() +}) + +test('cardinality', t => { + t.deepEqual(A.aggName.cardinality({ field: 'foo' }), { + aggName: { + cardinality: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.cardinality('foo'), { + aggName: { + cardinality: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('extendedStats', t => { + t.deepEqual(A.aggName.extendedStats({ field: 'foo' }), { + aggName: { + extended_stats: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.extendedStats('foo'), { + aggName: { + extended_stats: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('geoBounds', t => { + t.deepEqual(A.aggName.geoBounds({ field: 'foo' }), { + aggName: { + geo_bounds: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.geoBounds('foo'), { + aggName: { + geo_bounds: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('geoCentroid', t => { + t.deepEqual(A.aggName.geoCentroid({ field: 'foo' }), { + aggName: { + geo_centroid: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.geoCentroid('foo'), { + aggName: { + geo_centroid: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('max', t => { + t.deepEqual(A.aggName.max({ field: 'foo' }), { + aggName: { + max: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.max('foo'), { + aggName: { + max: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('min', t => { + t.deepEqual(A.aggName.min({ field: 'foo' }), { + aggName: { + min: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.min('foo'), { + aggName: { + min: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('percentiles', t => { + t.deepEqual(A.aggName.percentiles({ field: 'foo' }), { + aggName: { + percentiles: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.percentiles('foo'), { + aggName: { + percentiles: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('percentileRanks', t => { + t.deepEqual(A.aggName.percentileRanks({ field: 'foo' }), { + aggName: { + percentile_ranks: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.percentileRanks('foo'), + shorthandError + ) + + t.end() +}) + +test('scriptedMetric', t => { + t.deepEqual(A.aggName.scriptedMetric({ field: 'foo' }), { + aggName: { + scripted_metric: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.scriptedMetric('foo'), + shorthandError + ) + + t.end() +}) + +test('stats', t => { + t.deepEqual(A.aggName.stats({ field: 'foo' }), { + aggName: { + stats: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.stats('foo'), { + aggName: { + stats: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('sum', t => { + t.deepEqual(A.aggName.sum({ field: 'foo' }), { + aggName: { + sum: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.sum('foo'), { + aggName: { + sum: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('topHits', t => { + t.deepEqual(A.aggName.topHits({ field: 'foo' }), { + aggName: { + top_hits: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.topHits('foo'), + shorthandError + ) + + t.end() +}) + +test('valueCount', t => { + t.deepEqual(A.aggName.valueCount({ field: 'foo' }), { + aggName: { + value_count: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.valueCount('foo'), { + aggName: { + value_count: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('medianAbsoluteDeviation', t => { + t.deepEqual(A.aggName.medianAbsoluteDeviation({ field: 'foo' }), { + aggName: { + median_absolute_deviation: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.medianAbsoluteDeviation('foo'), { + aggName: { + median_absolute_deviation: { + field: 'foo' + } + } + }) + + t.end() +}) + +test('adjacencyMatrix', t => { + t.deepEqual(A.aggName.adjacencyMatrix({ field: 'foo' }), { + aggName: { + adjacency_matrix: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.adjacencyMatrix('foo'), + shorthandError + ) + + const agg = A.aggName.adjacencyMatrix( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + adjacency_matrix: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('autoDateHistogram', t => { + t.deepEqual(A.aggName.autoDateHistogram({ field: 'foo' }), { + aggName: { + auto_date_histogram: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.autoDateHistogram('foo'), { + aggName: { + auto_date_histogram: { + field: 'foo' + } + } + }) + + const agg = A.aggName.autoDateHistogram( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + auto_date_histogram: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('children', t => { + t.deepEqual(A.aggName.children({ type: 'foo' }), { + aggName: { + children: { + type: 'foo' + } + } + }) + + t.deepEqual(A.aggName.children('foo'), { + aggName: { + children: { + type: 'foo' + } + } + }) + + const agg = A.aggName.children( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + children: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('composite', t => { + t.deepEqual(A.aggName.composite({ field: 'foo' }), { + aggName: { + composite: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.composite('foo'), + shorthandError + ) + + const agg = A.aggName.composite( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + composite: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('dateHistogram', t => { + t.deepEqual(A.aggName.dateHistogram({ field: 'foo' }), { + aggName: { + date_histogram: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.dateHistogram('foo'), + shorthandError + ) + + const agg = A.aggName.dateHistogram( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + date_histogram: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('dateRange', t => { + t.deepEqual(A.aggName.dateRange({ field: 'foo' }), { + aggName: { + date_range: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.dateRange('foo'), + shorthandError + ) + + const agg = A.aggName.dateRange( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + date_range: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('diversifiedSampler', t => { + t.deepEqual(A.aggName.diversifiedSampler({ field: 'foo' }), { + aggName: { + diversified_sampler: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.diversifiedSampler('foo'), { + aggName: { + diversified_sampler: { + field: 'foo' + } + } + }) + + const agg = A.aggName.diversifiedSampler( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + diversified_sampler: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('filter', t => { + t.deepEqual(A.aggName.filter({ field: 'foo' }), { + aggName: { + filter: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.filter('foo'), + shorthandError + ) + + const agg = A.aggName.filter( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + filter: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('filters', t => { + t.deepEqual(A.aggName.filters({ field: 'foo' }), { + aggName: { + filters: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.filters('foo'), + shorthandError + ) + + const agg = A.aggName.filters( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + filters: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('geoDistance', t => { + t.deepEqual(A.aggName.geoDistance({ field: 'foo' }), { + aggName: { + geo_distance: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.geoDistance('foo'), + shorthandError + ) + + const agg = A.aggName.geoDistance( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + geo_distance: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('geohashGrid', t => { + t.deepEqual(A.aggName.geohashGrid({ field: 'foo' }), { + aggName: { + geohash_grid: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.geohashGrid('foo'), { + aggName: { + geohash_grid: { + field: 'foo' + } + } + }) + + const agg = A.aggName.geohashGrid( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + geohash_grid: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('geotileGrid', t => { + t.deepEqual(A.aggName.geotileGrid({ field: 'foo' }), { + aggName: { + geotile_grid: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.geotileGrid('foo'), { + aggName: { + geotile_grid: { + field: 'foo' + } + } + }) + + const agg = A.aggName.geotileGrid( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + geotile_grid: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('global', t => { + t.deepEqual(A.aggName.global({}), { + aggName: { + global: {} + } + }) + + t.throws( + () => A.aggName.global('foo'), + shorthandError + ) + + const agg = A.aggName.global( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + global: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('histogram', t => { + t.deepEqual(A.aggName.histogram({ field: 'foo' }), { + aggName: { + histogram: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.histogram('foo'), + shorthandError + ) + + const agg = A.aggName.histogram( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + histogram: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('ipRange', t => { + t.deepEqual(A.aggName.ipRange({ field: 'foo' }), { + aggName: { + ip_range: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.ipRange('foo'), + shorthandError + ) + + const agg = A.aggName.ipRange( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + ip_range: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('missing', t => { + t.deepEqual(A.aggName.missing({ field: 'foo' }), { + aggName: { + missing: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.missing('foo'), { + aggName: { + missing: { + field: 'foo' + } + } + }) + + const agg = A.aggName.missing( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + missing: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('nested', t => { + t.deepEqual(A.aggName.nested({ path: 'foo' }), { + aggName: { + nested: { + path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.nested('foo'), { + aggName: { + nested: { + path: 'foo' + } + } + }) + + const agg = A.aggName.nested( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + nested: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('parent', t => { + t.deepEqual(A.aggName.parent({ type: 'foo' }), { + aggName: { + parent: { + type: 'foo' + } + } + }) + + t.deepEqual(A.aggName.parent('foo'), { + aggName: { + parent: { + type: 'foo' + } + } + }) + + const agg = A.aggName.parent( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + parent: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('range', t => { + t.deepEqual(A.aggName.range({ field: 'foo' }), { + aggName: { + range: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.range('foo'), + shorthandError + ) + + const agg = A.aggName.range( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + range: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('reverseNested', t => { + t.deepEqual(A.aggName.reverseNested({ field: 'foo' }), { + aggName: { + reverse_nested: { + field: 'foo' + } + } + }) + + t.throws( + () => A.aggName.reverseNested('foo'), + shorthandError + ) + + const agg = A.aggName.reverseNested( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + reverse_nested: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('sampler', t => { + t.deepEqual(A.aggName.sampler({ shard_size: 42 }), { + aggName: { + sampler: { + shard_size: 42 + } + } + }) + + t.throws( + () => A.aggName.sampler('foo'), + shorthandError + ) + + const agg = A.aggName.sampler( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + sampler: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('significantTerms', t => { + t.deepEqual(A.aggName.significantTerms({ field: 'foo' }), { + aggName: { + significant_terms: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.significantTerms('foo'), { + aggName: { + significant_terms: { + field: 'foo' + } + } + }) + + const agg = A.aggName.significantTerms( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + significant_terms: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('significantText', t => { + t.deepEqual(A.aggName.significantText({ field: 'foo' }), { + aggName: { + significant_text: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.significantText('foo'), { + aggName: { + significant_text: { + field: 'foo' + } + } + }) + + const agg = A.aggName.significantText( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + significant_text: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('terms', t => { + t.deepEqual(A.aggName.terms({ field: 'foo' }), { + aggName: { + terms: { + field: 'foo' + } + } + }) + + t.deepEqual(A.aggName.terms('foo'), { + aggName: { + terms: { + field: 'foo' + } + } + }) + + const agg = A.aggName.terms( + { field: 'foo' }, + A.sumAgg.sum('bar'), + A.avgAgg.avg('baz') + ) + t.deepEqual(agg, { + aggName: { + terms: { + field: 'foo' + }, + aggs: { + sumAgg: { + sum: { field: 'bar' } + }, + avgAgg: { + avg: { field: 'baz' } + } + } + } + }) + + t.end() +}) + +test('avgBucket', t => { + t.deepEqual(A.aggName.avgBucket({ buckets_path: 'foo' }), { + aggName: { + avg_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.avgBucket('foo'), { + aggName: { + avg_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('derivative', t => { + t.deepEqual(A.aggName.derivative({ buckets_path: 'foo' }), { + aggName: { + derivative: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.derivative('foo'), { + aggName: { + derivative: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('maxBucket', t => { + t.deepEqual(A.aggName.maxBucket({ buckets_path: 'foo' }), { + aggName: { + max_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.maxBucket('foo'), { + aggName: { + max_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('minBucket', t => { + t.deepEqual(A.aggName.minBucket({ buckets_path: 'foo' }), { + aggName: { + min_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.minBucket('foo'), { + aggName: { + min_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('sumBucket', t => { + t.deepEqual(A.aggName.sumBucket({ buckets_path: 'foo' }), { + aggName: { + sum_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.sumBucket('foo'), { + aggName: { + sum_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('statsBucket', t => { + t.deepEqual(A.aggName.statsBucket({ buckets_path: 'foo' }), { + aggName: { + stats_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.statsBucket('foo'), { + aggName: { + stats_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('extendedStatsBucket', t => { + t.deepEqual(A.aggName.extendedStatsBucket({ buckets_path: 'foo' }), { + aggName: { + extended_stats_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.extendedStatsBucket('foo'), { + aggName: { + extended_stats_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('percentilesBucket', t => { + t.deepEqual(A.aggName.percentilesBucket({ buckets_path: 'foo' }), { + aggName: { + percentiles_bucket: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.percentilesBucket('foo'), { + aggName: { + percentiles_bucket: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('movingAvg', t => { + t.deepEqual(A.aggName.movingAvg({ buckets_path: 'foo' }), { + aggName: { + moving_avg: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.movingAvg('foo'), { + aggName: { + moving_avg: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('movingFn', t => { + t.deepEqual(A.aggName.movingFn({ buckets_path: 'foo' }), { + aggName: { + moving_fn: { + buckets_path: 'foo' + } + } + }) + + t.throws( + () => A.aggName.movingFn('foo'), + shorthandError + ) + + t.end() +}) + +test('cumulativeSum', t => { + t.deepEqual(A.aggName.cumulativeSum({ buckets_path: 'foo' }), { + aggName: { + cumulative_sum: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.cumulativeSum('foo'), { + aggName: { + cumulative_sum: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('bucketScript', t => { + t.deepEqual(A.aggName.bucketScript({ buckets_path: 'foo' }), { + aggName: { + bucket_script: { + buckets_path: 'foo' + } + } + }) + + t.throws( + () => A.aggName.bucketScript('foo'), + shorthandError + ) + + t.end() +}) + +test('bucketSelector', t => { + t.deepEqual(A.aggName.bucketSelector({ buckets_path: 'foo' }), { + aggName: { + bucket_selector: { + buckets_path: 'foo' + } + } + }) + + t.throws( + () => A.aggName.bucketSelector('foo'), + shorthandError + ) + + t.end() +}) + +test('bucketSort', t => { + t.deepEqual(A.aggName.bucketSort({ buckets_path: 'foo' }), { + aggName: { + bucket_sort: { + buckets_path: 'foo' + } + } + }) + + t.throws( + () => A.aggName.bucketSort('foo'), + shorthandError + ) + + t.end() +}) + +test('serialDiff', t => { + t.deepEqual(A.aggName.serialDiff({ buckets_path: 'foo' }), { + aggName: { + serial_diff: { + buckets_path: 'foo' + } + } + }) + + t.deepEqual(A.aggName.serialDiff('foo'), { + aggName: { + serial_diff: { + buckets_path: 'foo' + } + } + }) + + t.end() +}) + +test('matrixStats', t => { + t.deepEqual(A.aggName.matrixStats({ fields: 'foo' }), { + aggName: { + matrix_stats: { + fields: 'foo' + } + } + }) + + t.deepEqual(A.aggName.matrixStats('foo'), { + aggName: { + matrix_stats: { + fields: 'foo' + } + } + }) + + t.end() +}) diff --git a/test/dsl/bool-optimize.test.ts b/test/dsl/bool-optimize.test.ts new file mode 100644 index 000000000..f8a2e0065 --- /dev/null +++ b/test/dsl/bool-optimize.test.ts @@ -0,0 +1,777 @@ +'use strict' + +import { test } from 'tap' +import { Q } from '../../dsl' + +test('must only query', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.must( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.bool( + Q.must( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('must and must_not query', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.bool( + Q.must( + Q.match('9', '10'), + Q.term('11', '12') + ) + ), + Q.bool( + Q.mustNot( + Q.match('13', '14'), + Q.term('15', '16') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { match: { 9: '10' } }, + { term: { 11: '12' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 13: '14' } }, + { term: { 15: '16' } } + ] + } + } + }) + + t.end() +}) + +test('must and must_not query (mixed and nested)', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.bool( + Q.must( + Q.match('9', '10'), + Q.term('11', '12') + ) + ), + Q.bool( + Q.mustNot( + Q.match('13', '14') + ), + Q.must( + Q.term('15', '16') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { match: { 9: '10' } }, + { term: { 11: '12' } }, + { term: { 15: '16' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 13: '14' } } + ] + } + } + }) + + t.end() +}) + +test('must and should query', t => { + const query = Q.bool( + Q.must( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.should( + Q.match('5', '6'), + Q.term('7', '8') + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + should: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ] + } + } + }) + + t.end() +}) + +test('must and should query (nested) / 1', t => { + const query = Q.bool( + Q.must( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.must( + Q.bool( + Q.must( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.should( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { + bool: { + must: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ], + should: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + ] + } + } + }) + + t.end() +}) + +test('must and should query (nested) / 2', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.must( + Q.bool( + Q.must( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.should( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { + bool: { + must: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ], + should: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + ] + } + } + }) + + t.end() +}) + +test('must and filter query / 1', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.filter( + Q.bool( + Q.must( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + filter: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('must and filter query / 2', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.filter( + Q.bool( + Q.match('5', '6'), + Q.term('7', '8'), + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + filter: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('all but should query / 1', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.bool( + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ], + filter: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('all but should query / 2', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.bool( + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ], + filter: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('all but should query / 3', t => { + const query = Q.bool( + Q.mustNot( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.must( + Q.bool( + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + filter: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('all but should query / 4', t => { + const query = Q.bool( + Q.must( + Q.match('17', '18'), + Q.term('19', '20') + ), + Q.mustNot( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.must( + Q.bool( + Q.must( + Q.match('13', '14'), + Q.term('15', '16') + ), + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.filter( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 17: '18' } }, + { term: { 19: '20' } }, + { match: { 13: '14' } }, + { term: { 15: '16' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + filter: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + }) + + t.end() +}) + +test('filter with should', t => { + const query = Q.bool( + Q.filter( + Q.bool( + Q.must( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.should( + Q.match('5', '6'), + Q.term('7', '8') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + filter: [ + { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + should: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ] + } + } + ] + } + } + }) + + t.end() +}) + +test('nested with only should', t => { + const query = Q.bool( + Q.should( + Q.bool( + Q.should( + Q.match('1', '2'), + Q.term('3', '4') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + should: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ] + } + } + }) + + t.end() +}) + +test('nested with only should and minimum_should_match', t => { + const query = Q.bool( + Q.should( + Q.bool( + Q.should( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.minShouldMatch(1) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + should: [{ + bool: { + should: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + minimum_should_match: 1 + } + }] + } + } + }) + + t.end() +}) + +test('nested with should and other clause', t => { + const query = Q.bool( + Q.should( + Q.bool( + Q.should( + Q.match('1', '2'), + Q.term('3', '4') + ), + Q.mustNot( + Q.match('5', '6'), + Q.term('7', '8') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + should: [{ + bool: { + should: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + must_not: [ + { match: { 5: '6' } }, + { term: { 7: '8' } } + ] + } + }] + } + } + }) + + t.end() +}) + +test('nested with only should', t => { + const query = Q.bool( + Q.should( + Q.match('1', '2') + ), + Q.should( + Q.term('3', '4') + ) + ) + + t.deepEqual(query, { + query: { + bool: { + should: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ] + } + } + }) + + t.end() +}) + +test('nested with only should and minimum_should_match', t => { + const query = Q.bool( + Q.should( + Q.match('1', '2') + ), + Q.should( + Q.term('3', '4') + ), + Q.minShouldMatch(1) + ) + + t.deepEqual(query, { + query: { + bool: { + should: [ + { match: { 1: '2' } }, + { term: { 3: '4' } } + ], + minimum_should_match: 1 + } + } + }) + + t.end() +}) + +test('Should not merge up named queries / 1', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.must( + Q.match('5', '6'), + Q.term('7', '8') + ), + Q.bool( + Q.name('test'), + Q.must( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { + bool: { + _name: 'test', + must: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + ] + } + } + }) + + t.end() +}) + +test('Should not merge up named queries / 2', t => { + const query = Q.bool( + Q.match('1', '2'), + Q.term('3', '4'), + Q.must( + Q.match('5', '6'), + Q.term('7', '8'), + Q.bool( + Q.name('test'), + Q.must( + Q.match('9', '10'), + Q.term('11', '12') + ) + ) + ) + ) + + t.deepEqual(query, { + query: { + bool: { + must: [ + { match: { 1: '2' } }, + { term: { 3: '4' } }, + { match: { 5: '6' } }, + { term: { 7: '8' } }, + { + bool: { + _name: 'test', + must: [ + { match: { 9: '10' } }, + { term: { 11: '12' } } + ] + } + } + ] + } + } + }) + + t.end() +}) + +test('should throw if it can\'t merge the query', t => { + try { + Q.bool( + Q.must(), + Q.must(), + Q.should() + ) + t.fail('It should throw') + } catch (err) { + t.is(err.message, 'Cannot merge this query') + } + + t.end() +}) diff --git a/test/dsl/boolean-and-helpers.test.ts b/test/dsl/boolean-and-helpers.test.ts new file mode 100644 index 000000000..23eb213b8 --- /dev/null +++ b/test/dsl/boolean-and-helpers.test.ts @@ -0,0 +1,350 @@ +'use strict' + +import { test } from 'tap' +import { Q } from '../../dsl' + +test('AND', t => { + t.test('Bool and Bool', t => { + noShouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))) + ) + + shouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + sameClauseNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.must(Q.term('baz', 'faz'))) + ) + + sameClauseYesShould( + t, + Q.bool(Q.should(Q.match('foo', 'bar'))), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + moreNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))), + Q.bool(Q.filter(Q.term('winter', 'is coming'))) + ) + + moreYesShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))), + Q.bool(Q.should(Q.term('winter', 'is coming'))) + ) + + t.end() + }) + + t.test('Bool and Clause', t => { + noShouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')) + ) + + shouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.should(Q.term('baz', 'faz')) + ) + + sameClauseNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.must(Q.term('baz', 'faz')) + ) + + sameClauseYesShould( + t, + Q.bool(Q.should(Q.match('foo', 'bar'))), + Q.should(Q.term('baz', 'faz')) + ) + + moreNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')), + Q.filter(Q.term('winter', 'is coming')) + ) + + moreYesShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')), + Q.should(Q.term('winter', 'is coming')) + ) + + t.end() + }) + + t.test('Clause and Bool', t => { + noShouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.filter(Q.term('baz', 'faz'))) + ) + + shouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + sameClauseNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.must(Q.term('baz', 'faz'))) + ) + + sameClauseYesShould( + t, + Q.should(Q.match('foo', 'bar')), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + moreNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.bool(Q.filter(Q.term('winter', 'is coming'))) + ) + + moreYesShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.bool(Q.should(Q.term('winter', 'is coming'))) + ) + + t.end() + }) + + t.test('Clause and Clause', t => { + noShouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')) + ) + + shouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.should(Q.term('baz', 'faz')) + ) + + sameClauseNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.must(Q.term('baz', 'faz')) + ) + + sameClauseYesShould( + t, + Q.should(Q.match('foo', 'bar')), + Q.should(Q.term('baz', 'faz')) + ) + + moreNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.filter(Q.term('winter', 'is coming')) + ) + + moreYesShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.should(Q.term('winter', 'is coming')) + ) + + t.end() + }) + + t.test('Bool and Condition', t => { + const query1 = Q.bool(Q.must(Q.match('foo', 'bar'))) + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + + t.test('Bool (with should) and Condition', t => { + const query1 = Q.bool(Q.should(Q.match('foo', 'bar'))) + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [{ term: { baz: 'faz' } }], + should: [{ match: { foo: 'bar' } }] + } + } + }) + + t.end() + }) + + t.test('Condition and Condition', t => { + const query1 = Q.match('foo', 'bar') + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + + t.end() + + function noShouldClauses (t, query1, query2) { + t.test('No should clauses', t => { + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [{ match: { foo: 'bar' } }], + filter: [{ term: { baz: 'faz' } }] + } + } + }) + + t.end() + }) + } + + function shouldClauses (t, query1, query2) { + t.test('Should clauses', t => { + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [ + { match: { foo: 'bar' } }, + { + bool: { + should: [ + { term: { baz: 'faz' } } + ] + } + } + ] + } + } + }) + + t.end() + }) + } + + function sameClauseNoShould (t, query1, query2) { + t.test('same clauses without should', t => { + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + } + + function sameClauseYesShould (t, query1, query2) { + t.test('same clauses with should', t => { + t.deepEqual(Q.and(query1, query2), { + query: { + bool: { + must: [ + { + bool: { + should: [ + { term: { baz: 'faz' } } + ] + } + } + ], + should: [ + { match: { foo: 'bar' } } + ] + } + } + }) + + t.end() + }) + } + + function moreNoShould (t, query1, query2, query3) { + t.test('More than two clauses without should', t => { + t.deepEqual(Q.and(query1, query2, query3), { + query: { + bool: { + must: [{ match: { foo: 'bar' } }], + filter: [ + { term: { baz: 'faz' } }, + { term: { winter: 'is coming' } } + ] + } + } + }) + + t.end() + }) + } + + function moreYesShould (t, query1, query2, query3) { + t.test('More than two clauses with should', t => { + t.deepEqual(Q.and(query1, query2, query3), { + query: { + bool: { + must: [ + { match: { foo: 'bar' } }, + { + bool: { + should: [ + { term: { winter: 'is coming' } } + ] + } + } + ], + filter: [{ term: { baz: 'faz' } }] + } + } + }) + + t.end() + }) + } +}) diff --git a/test/dsl/boolean-not-helpers.test.ts b/test/dsl/boolean-not-helpers.test.ts new file mode 100644 index 000000000..c53fccf89 --- /dev/null +++ b/test/dsl/boolean-not-helpers.test.ts @@ -0,0 +1,171 @@ +'use strict' + +import { test } from 'tap' +import { Q } from '../../dsl' + +test('NOT', t => { + t.test('Bool query', t => { + const query = Q.bool( + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')) + ) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + bool: { + must: [{ match: { foo: 'bar' } }], + filter: [{ term: { baz: 'faz' } }] + } + }] + } + } + }) + + t.end() + }) + + t.test('Bool query (with must_not)', t => { + const query = Q.bool( + Q.must(Q.match('foo', 'bar')), + Q.mustNot(Q.term('baz', 'faz')) + ) + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ match: { foo: 'bar' } }], + must: [{ term: { baz: 'faz' } }] + } + } + }) + + t.end() + }) + + t.test('Bool query (only must)', t => { + const query = Q.bool( + Q.must(Q.match('foo', 'bar')) + ) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + match: { foo: 'bar' } + }] + } + } + }) + + t.end() + }) + + t.test('Bool query (only must_not)', t => { + const query = Q.bool( + Q.mustNot(Q.match('foo', 'bar')) + ) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must: [{ + match: { foo: 'bar' } + }] + } + } + }) + + t.end() + }) + + t.test('Must clause', t => { + const query = Q.must(Q.match('foo', 'bar')) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + match: { foo: 'bar' } + }] + } + } + }) + + t.end() + }) + + t.test('Should clause', t => { + const query = Q.should(Q.match('foo', 'bar')) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + bool: { + should: [{ + match: { foo: 'bar' } + }] + } + }] + } + } + }) + + t.end() + }) + + t.test('Filter clause', t => { + const query = Q.filter(Q.match('foo', 'bar')) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + bool: { + filter: [{ + match: { foo: 'bar' } + }] + } + }] + } + } + }) + + t.end() + }) + + t.test('Must clause', t => { + const query = Q.mustNot(Q.match('foo', 'bar')) + + t.deepEqual(Q.not(query), { + query: { + bool: { + must: [{ + match: { foo: 'bar' } + }] + } + } + }) + + t.end() + }) + + t.test('Condition', t => { + const query = Q.match('foo', 'bar') + + t.deepEqual(Q.not(query), { + query: { + bool: { + must_not: [{ + match: { foo: 'bar' } + }] + } + } + }) + + t.end() + }) + + t.end() +}) diff --git a/test/dsl/boolean-or-helpers.test.ts b/test/dsl/boolean-or-helpers.test.ts new file mode 100644 index 000000000..ac78d880a --- /dev/null +++ b/test/dsl/boolean-or-helpers.test.ts @@ -0,0 +1,334 @@ +'use strict' + +import { test } from 'tap' +import { Q } from '../../dsl' + +test('OR', t => { + t.test('Bool and Bool', t => { + noShouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))) + ) + + shouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + sameClauseNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.must(Q.term('baz', 'faz'))) + ) + + sameClauseYesShould( + t, + Q.bool(Q.should(Q.match('foo', 'bar'))), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + moreNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))), + Q.bool(Q.filter(Q.term('winter', 'is coming'))) + ) + + moreYesShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.bool(Q.filter(Q.term('baz', 'faz'))), + Q.bool(Q.should(Q.term('winter', 'is coming'))) + ) + + t.end() + }) + + t.test('Bool and Clause', t => { + noShouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')) + ) + + shouldClauses( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.should(Q.term('baz', 'faz')) + ) + + sameClauseNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.must(Q.term('baz', 'faz')) + ) + + sameClauseYesShould( + t, + Q.bool(Q.should(Q.match('foo', 'bar'))), + Q.should(Q.term('baz', 'faz')) + ) + + moreNoShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')), + Q.filter(Q.term('winter', 'is coming')) + ) + + moreYesShould( + t, + Q.bool(Q.must(Q.match('foo', 'bar'))), + Q.filter(Q.term('baz', 'faz')), + Q.should(Q.term('winter', 'is coming')) + ) + + t.end() + }) + + t.test('Clause and Bool', t => { + noShouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.filter(Q.term('baz', 'faz'))) + ) + + shouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + sameClauseNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.bool(Q.must(Q.term('baz', 'faz'))) + ) + + sameClauseYesShould( + t, + Q.should(Q.match('foo', 'bar')), + Q.bool(Q.should(Q.term('baz', 'faz'))) + ) + + moreNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.bool(Q.filter(Q.term('winter', 'is coming'))) + ) + + moreYesShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.bool(Q.should(Q.term('winter', 'is coming'))) + ) + + t.end() + }) + + t.test('Clause and Clause', t => { + noShouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')) + ) + + shouldClauses( + t, + Q.must(Q.match('foo', 'bar')), + Q.should(Q.term('baz', 'faz')) + ) + + sameClauseNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.must(Q.term('baz', 'faz')) + ) + + sameClauseYesShould( + t, + Q.should(Q.match('foo', 'bar')), + Q.should(Q.term('baz', 'faz')) + ) + + moreNoShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.filter(Q.term('winter', 'is coming')) + ) + + moreYesShould( + t, + Q.must(Q.match('foo', 'bar')), + Q.filter(Q.term('baz', 'faz')), + Q.should(Q.term('winter', 'is coming')) + ) + + t.end() + }) + + t.test('Bool and Condition', t => { + const query1 = Q.bool(Q.must(Q.match('foo', 'bar'))) + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + + t.test('Bool (with should) and Condition', t => { + const query1 = Q.bool(Q.should(Q.match('foo', 'bar'))) + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + + t.test('Condition and Condition', t => { + const query1 = Q.match('foo', 'bar') + const query2 = Q.term('baz', 'faz') + + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + + t.end() + + function noShouldClauses (t, query1, query2) { + t.test('No should clauses', t => { + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { bool: { filter: [{ term: { baz: 'faz' } }] } } + ] + } + } + }) + + t.end() + }) + } + + function shouldClauses (t, query1, query2) { + t.test('Should clauses', t => { + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + } + + function sameClauseNoShould (t, query1, query2) { + t.test('same clauses without should', t => { + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { bool: { must: [{ term: { baz: 'faz' } }] } } + ] + } + } + }) + + t.end() + }) + } + + function sameClauseYesShould (t, query1, query2) { + t.test('same clauses with should', t => { + t.deepEqual(Q.or(query1, query2), { + query: { + bool: { + should: [ + { match: { foo: 'bar' } }, + { term: { baz: 'faz' } } + ] + } + } + }) + + t.end() + }) + } + + function moreNoShould (t, query1, query2, query3) { + t.test('More than two clauses without should', t => { + t.deepEqual(Q.or(query1, query2, query3), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { bool: { filter: [{ term: { baz: 'faz' } }] } }, + { bool: { filter: [{ term: { winter: 'is coming' } }] } } + ] + } + } + }) + + t.end() + }) + } + + function moreYesShould (t, query1, query2, query3) { + t.test('More than two clauses with should', t => { + t.deepEqual(Q.or(query1, query2, query3), { + query: { + bool: { + should: [ + { bool: { must: [{ match: { foo: 'bar' } }] } }, + { bool: { filter: [{ term: { baz: 'faz' } }] } }, + { term: { winter: 'is coming' } } + ] + } + } + }) + + t.end() + }) + } +}) diff --git a/test/dsl/query-helpers.test.ts b/test/dsl/query-helpers.test.ts new file mode 100644 index 000000000..37798865c --- /dev/null +++ b/test/dsl/query-helpers.test.ts @@ -0,0 +1,792 @@ +'use strict' + +import { test } from 'tap' +/* eslint-disable no-unused-vars */ +import * as types from '../../dsl/lib/types' +/* eslint-enable no-unused-vars */ +import { Q } from '../../dsl' + +test('Q is a function that creates the final query object', t => { + t.type(Q, 'function') + + t.deepEqual(Q({ a: 1 }, { b: 2 }, { c: 3 }), { + query: { + bool: { + must: [ + { a: 1 }, + { b: 2 }, + { c: 3 } + ] + } + } + }) + + t.end() +}) + +test('Compile a query', t => { + t.type(Q.param, 'function') + t.type(Q.compile, 'function') + + const query = Q( + { a: Q.param('a') }, + { b: Q.param('b') }, + { c: Q.param('c') } + ) + + interface Input { + a: number, + b: number, + c: number + } + const compiledQuery = Q.compile(query) + + t.deepEqual(compiledQuery({ a: 1, b: 2, c: 3 }), { + query: { + bool: { + must: [ + { a: 1 }, + { b: 2 }, + { c: 3 } + ] + } + } + }) + + t.end() +}) + +test('match returns a match query', t => { + t.type(Q.match, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.match('foo', 'bar'), { + match: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.match('foo', 'bar', { operator: 'and' }), { + match: { + foo: { + query: 'bar', + operator: 'and' + } + } + }) + t.end() + }) + + t.end() +}) + +test('matchPhrase returns a match_phrase query', t => { + t.type(Q.matchPhrase, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.matchPhrase('foo', 'bar'), { + match_phrase: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.matchPhrase('foo', 'bar', { analyzer: 'test' }), { + match_phrase: { + foo: { + query: 'bar', + analyzer: 'test' + } + } + }) + t.end() + }) + + t.end() +}) + +test('matchPhrasePrefix returns a match_phrase_prefix query', t => { + t.type(Q.matchPhrasePrefix, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.matchPhrasePrefix('foo', 'bar'), { + match_phrase_prefix: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.matchPhrasePrefix('foo', 'bar', { max_expansions: 10 }), { + match_phrase_prefix: { + foo: { + query: 'bar', + max_expansions: 10 + } + } + }) + t.end() + }) + + t.end() +}) + +test('multiMatch returns a multi_match query', t => { + t.type(Q.multiMatch, 'function') + + t.deepEqual(Q.multiMatch(['foo', 'baz'], 'bar', { type: 'best_fields' }), { + multi_match: { + query: 'bar', + fields: ['foo', 'baz'], + type: 'best_fields' + } + }) + + t.end() +}) + +test('matchAll returns a match_all query', t => { + t.type(Q.matchAll, 'function') + + t.deepEqual(Q.matchAll({ boost: 1.2 }), { + match_all: { boost: 1.2 } + }) + + t.end() +}) + +test('matchNone returns a match_none query', t => { + t.type(Q.matchNone, 'function') + + t.deepEqual(Q.matchNone(), { + match_none: {} + }) + + t.end() +}) + +test('common returns a common query', t => { + t.type(Q.common, 'function') + + t.deepEqual(Q.common('foo', 'bar', { cutoff_frequency: 0.001 }), { + common: { + foo: { + query: 'bar', + cutoff_frequency: 0.001 + } + } + }) + + t.end() +}) + +test('queryString returns a query_string query', t => { + t.type(Q.queryString, 'function') + + t.deepEqual(Q.queryString('foo', { default_field: 'content' }), { + query_string: { + query: 'foo', + default_field: 'content' + } + }) + + t.end() +}) + +test('simpleQueryString returns a simple_query_string query', t => { + t.type(Q.simpleQueryString, 'function') + + t.deepEqual(Q.simpleQueryString('foo', { default_field: 'content' }), { + simple_query_string: { + query: 'foo', + default_field: 'content' + } + }) + + t.end() +}) + +test('term returns a term query', t => { + t.type(Q.term, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.term('foo', 'bar'), { + term: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.term('foo', 'bar', { boost: 2.0 }), { + term: { + foo: { + value: 'bar', + boost: 2.0 + } + } + }) + t.end() + }) + + t.end() +}) + +test('terms returns a terms query', t => { + t.type(Q.terms, 'function') + + t.deepEqual(Q.terms('foo', ['bar', 'baz']), { + terms: { foo: ['bar', 'baz'] } + }) + + t.end() +}) + +test('termsSet returns a terms_set query', t => { + t.type(Q.termsSet, 'function') + + t.deepEqual(Q.termsSet('foo', ['bar', 'baz'], { minimum_should_match_field: 'required_matches' }), { + terms_set: { + foo: { + terms: ['bar', 'baz'], + minimum_should_match_field: 'required_matches' + } + } + }) + + t.end() +}) + +test('range returns a range query', t => { + t.type(Q.range, 'function') + + t.deepEqual(Q.range('foo', { gte: 2 }), { + range: { foo: { gte: 2 } } + }) + + t.end() +}) + +test('exists returns a exists query', t => { + t.type(Q.exists, 'function') + + t.deepEqual(Q.exists('foo'), { + exists: { field: 'foo' } + }) + + t.end() +}) + +test('prefix returns a prefix query', t => { + t.type(Q.prefix, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.prefix('foo', 'bar'), { + prefix: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.prefix('foo', 'bar', { boost: 2.0 }), { + prefix: { + foo: { + value: 'bar', + boost: 2.0 + } + } + }) + t.end() + }) + + t.end() +}) + +test('wildcard returns a wildcard query', t => { + t.type(Q.wildcard, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.wildcard('foo', 'bar'), { + wildcard: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.wildcard('foo', 'bar', { boost: 2.0 }), { + wildcard: { + foo: { + value: 'bar', + boost: 2.0 + } + } + }) + t.end() + }) + + t.end() +}) + +test('regexp returns a regexp query', t => { + t.type(Q.regexp, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.regexp('foo', 'bar'), { + regexp: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.regexp('foo', 'bar', { boost: 2.0 }), { + regexp: { + foo: { + value: 'bar', + boost: 2.0 + } + } + }) + t.end() + }) + + t.end() +}) + +test('fuzzy returns a fuzzy query', t => { + t.type(Q.fuzzy, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.fuzzy('foo', 'bar'), { + fuzzy: { foo: 'bar' } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.fuzzy('foo', 'bar', { boost: 2.0 }), { + fuzzy: { + foo: { + value: 'bar', + boost: 2.0 + } + } + }) + t.end() + }) + + t.end() +}) + +test('ids returns a ids query', t => { + t.type(Q.ids, 'function') + + t.deepEqual(Q.ids('foo', ['bar', 'baz'], { type: '_doc' }), { + ids: { + foo: { + values: ['bar', 'baz'], + type: '_doc' + } + } + }) + + t.end() +}) + +test('must returns a must block', t => { + t.type(Q.must, 'function') + + t.deepEqual(Q.must(c('foo'), c('bar'), c('baz')), { + must: [c('foo'), c('bar'), c('baz')] + }) + + // should flat arrays + t.deepEqual(Q.must(c('foo'), [c('bar')], c('baz')), { + must: [c('foo'), c('bar'), c('baz')] + }) + + t.deepEqual( + Q.must( + c('foo'), + Q.must(c('bar')), + Q.bool(Q.must(c('baz'))) + ), + { must: [c('foo'), c('bar'), c('baz')] } + ) + + t.deepEqual( + Q.must( + c('foo'), + Q.must(c('bar'), Q.bool(Q.must(c('faz')))), + Q.bool(Q.must(c('baz'))) + ), + { must: [c('foo'), c('bar'), c('faz'), c('baz')] } + ) + + t.deepEqual( + Q.must( + c('foo'), + Q.must(c('bar')), + Q.bool(Q.should(c('baz'))) + ), + { must: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.deepEqual( + Q.must( + c('foo'), + Q.must(c('bar')), + Q.should(c('baz')) + ), + { must: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.end() +}) + +test('should returns a should block', t => { + t.type(Q.should, 'function') + + t.deepEqual(Q.should(c('foo'), c('bar'), c('baz')), { + should: [c('foo'), c('bar'), c('baz')] + }) + + // should flat arrays + t.deepEqual(Q.should(c('foo'), [c('bar')], c('baz')), { + should: [c('foo'), c('bar'), c('baz')] + }) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar')), + Q.bool(Q.should(c('baz'))) + ), + { should: [c('foo'), c('bar'), c('baz')] } + ) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar'), Q.bool(Q.should(c('faz')))), + Q.bool(Q.should(c('baz'))) + ), + { should: [c('foo'), c('bar'), c('faz'), c('baz')] } + ) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar')), + Q.bool(Q.must(c('baz'))) + ), + { should: [c('foo'), c('bar'), { bool: Q.must(c('baz')) }] } + ) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar')), + Q.must(c('baz')) + ), + { should: [c('foo'), c('bar'), { bool: Q.must(c('baz')) }] } + ) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar')), + Q.bool(Q.should(c('baz'), c('faz')), { minimum_should_match: 1 }) + ), + { + should: [ + c('foo'), c('bar'), + { bool: { ...Q.should(c('baz'), c('faz')), minimum_should_match: 1 } } + ] + } + ) + + t.deepEqual( + Q.should( + c('foo'), + Q.should(c('bar')), + { ...Q.should(c('baz'), c('faz')), minimum_should_match: 1 } + ), + { + should: [ + c('foo'), c('bar'), + { bool: { ...Q.should(c('baz'), c('faz')), minimum_should_match: 1 } } + ] + } + ) + + t.deepEqual( + Q.should( + c('foo'), + { ...Q.should(c('bar1'), c('bar2')), minimum_should_match: 1 }, + Q.bool(Q.should(c('baz1'), c('baz2')), { minimum_should_match: 1 }) + ), + { + should: [ + c('foo'), + { bool: { ...Q.should(c('bar1'), c('bar2')), minimum_should_match: 1 } }, + { bool: { ...Q.should(c('baz1'), c('baz2')), minimum_should_match: 1 } } + ] + } + ) + + t.end() +}) + +test('mustNot returns a must_not block', t => { + t.type(Q.mustNot, 'function') + + t.deepEqual(Q.mustNot(c('foo'), c('bar'), c('baz')), { + must_not: [c('foo'), c('bar'), c('baz')] + }) + + // should flat arrays + t.deepEqual(Q.mustNot(c('foo'), [c('bar')], c('baz')), { + must_not: [c('foo'), c('bar'), c('baz')] + }) + + t.deepEqual( + Q.mustNot( + c('foo'), + Q.mustNot(c('bar')), + Q.bool(Q.mustNot(c('baz'))) + ), + { must_not: [c('foo'), c('bar'), c('baz')] } + ) + + t.deepEqual( + Q.mustNot( + c('foo'), + Q.mustNot(c('bar'), Q.bool(Q.mustNot(c('faz')))), + Q.bool(Q.mustNot(c('baz'))) + ), + { must_not: [c('foo'), c('bar'), c('faz'), c('baz')] } + ) + + t.deepEqual( + Q.mustNot( + c('foo'), + Q.mustNot(c('bar')), + Q.bool(Q.should(c('baz'))) + ), + { must_not: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.deepEqual( + Q.mustNot( + c('foo'), + Q.mustNot(c('bar')), + Q.should(c('baz')) + ), + { must_not: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.end() +}) + +test('filter returns a filter block', t => { + t.type(Q.filter, 'function') + + t.deepEqual(Q.filter(c('foo'), c('bar'), c('baz')), { + filter: [c('foo'), c('bar'), c('baz')] + }) + + // should flat arrays + t.deepEqual(Q.filter(c('foo'), [c('bar')], c('baz')), { + filter: [c('foo'), c('bar'), c('baz')] + }) + + t.deepEqual( + Q.filter( + c('foo'), + Q.filter(c('bar')), + Q.bool(Q.filter(c('baz'))) + ), + { filter: [c('foo'), c('bar'), c('baz')] } + ) + + t.deepEqual( + Q.filter( + c('foo'), + Q.filter(c('bar'), Q.bool(Q.filter(c('faz')))), + Q.bool(Q.filter(c('baz'))) + ), + { filter: [c('foo'), c('bar'), c('faz'), c('baz')] } + ) + + t.deepEqual( + Q.filter( + c('foo'), + Q.filter(c('bar')), + Q.bool(Q.should(c('baz'))) + ), + { filter: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.deepEqual( + Q.filter( + c('foo'), + Q.filter(c('bar')), + Q.should(c('baz')) + ), + { filter: [c('foo'), c('bar'), { bool: Q.should(c('baz')) }] } + ) + + t.end() +}) + +test('bool returns a bool query block', t => { + t.type(Q.bool, 'function') + + t.deepEqual(Q.bool(Q.must(c('foo')), Q.should(c('bar')), Q.filter(c('baz'))), { + query: { + bool: { + must: [c('foo')], + should: [c('bar')], + filter: [c('baz')] + } + } + }) + + t.deepEqual(Q.bool(), { query: { bool: {} } }) + + t.end() +}) + +test('nested returns a nested query block', t => { + t.type(Q.nested, 'function') + + const query = Q.bool(Q.must(c('foo')), Q.should(c('bar')), Q.filter(c('baz'))) + t.deepEqual(Q.nested('foo', query, { score_mode: 'max' }), { + query: { + nested: { + path: 'foo', + score_mode: 'max', + ...query + } + } + }) + + t.end() +}) + +test('constantScore returns a constant_score query block', t => { + t.type(Q.constantScore, 'function') + + const query = Q.bool(Q.must(c('foo')), Q.should(c('bar')), Q.filter(c('baz'))) + t.deepEqual(Q.constantScore(query, 2.0), { + query: { + constant_score: { + boost: 2.0, + ...query + } + } + }) + + t.end() +}) + +test('disMax returns a dis_max query block', t => { + t.type(Q.disMax, 'function') + + t.test('simple query', t => { + t.deepEqual(Q.disMax([{ a: 1 }, { b: 2 }, { c: 3 }]), { + query: { + dis_max: { + queries: [{ a: 1 }, { b: 2 }, { c: 3 }] + } + } + }) + t.end() + }) + + t.test('complex query', t => { + t.deepEqual(Q.disMax([{ a: 1 }, { b: 2 }, { c: 3 }], { tie_breaker: 1.0, boost: 1.0 }), { + query: { + dis_max: { + tie_breaker: 1.0, + boost: 1.0, + queries: [{ a: 1 }, { b: 2 }, { c: 3 }] + } + } + }) + t.end() + }) + + t.end() +}) + +test('functionScore returns a function_score query block', t => { + t.type(Q.functionScore, 'function') + + t.deepEqual(Q.functionScore({ foo: 'bar' }), { + query: { function_score: { foo: 'bar' } } + }) + + t.end() +}) + +test('boosting returns a boosting query block', t => { + t.type(Q.boosting, 'function') + + t.deepEqual(Q.boosting({ foo: 'bar' }), { + query: { boosting: { foo: 'bar' } } + }) + + t.end() +}) + +test('sort returns a sort block', t => { + t.type(Q.sort, 'function') + + t.test('simple sort', t => { + t.deepEqual(Q.sort('foo', { order: 'asc' }), { + sort: [{ foo: { order: 'asc' } }] + }) + t.end() + }) + + t.test('multiple sorts', t => { + t.deepEqual(Q.sort([{ foo: { order: 'asc' } }, { bar: { order: 'desc' } }]), { + sort: [ + { foo: { order: 'asc' } }, + { bar: { order: 'desc' } } + ] + }) + t.end() + }) + + t.end() +}) + +test('size', t => { + t.type(Q.size, 'function') + + t.deepEqual(Q.size(5), { size: 5 }) + + t.end() +}) + +test('minShouldMatch', t => { + t.type(Q.minShouldMatch, 'function') + + t.deepEqual(Q.minShouldMatch(5), { minimum_should_match: 5 }) + + t.end() +}) + +test('name', t => { + t.type(Q.name, 'function') + + t.deepEqual(Q.name('test'), { _name: 'test' }) + + t.end() +}) + +// build a condition bloc +function c (key: string): types.Condition { + return { [key]: key } +}