From e932366caf8b2314e8a98b7e8a2d786c02ac0061 Mon Sep 17 00:00:00 2001 From: delvedor Date: Mon, 14 Sep 2020 17:13:34 +0200 Subject: [PATCH] Fixed minor bugs and improved fluent api --- dsl/src/fluent.ts | 64 ++++++++++++++++++++++++++++++++++++----------- dsl/src/query.ts | 22 ++++++++-------- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/dsl/src/fluent.ts b/dsl/src/fluent.ts index 59ac35d5e..0561d0e59 100644 --- a/dsl/src/fluent.ts +++ b/dsl/src/fluent.ts @@ -29,6 +29,16 @@ import A from './aggregation' import * as t from './types' import T from '../es-types' +type SearchRequest = Required['body'] +interface BoolQuery { + filter?: T.QueryContainer[] + minimum_should_match?: T.MinimumShouldMatch + must?: T.QueryContainer[] + must_not?: T.QueryContainer[] + should?: T.QueryContainer[] + _name?: string +} + const kState = Symbol('dsl-query-state') type MultiType = string | number | boolean @@ -36,15 +46,20 @@ type MultiType = string | number | boolean // and automatically call `query.build()` class FluentQ { - [kState]: Record[] + [kState]: (SearchRequest | T.QueryContainer | T.QueryContainer[] | BoolQuery)[] constructor () { this[kState] = [] } - build (): Record { + build (): SearchRequest { return Q(...this[kState]) } + buildQuery (): T.QueryContainer { + const b = Q(...this[kState]) + return b.query != null ? b.query : {} + } + param (key: string): Symbol { return Q.param(key) } @@ -123,14 +138,16 @@ class FluentQ { term (key: string, val: (MultiType | Symbol)[]): this term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): this term (key: string, val: any, opts?: any): this { - if (Array.isArray(val)) { - return this.terms(key, val, opts) + if (Array.isArray(val) && opts == null) { + return this.terms(key, val) } this[kState].push(Q.term(key, val, opts)) return this } - terms (key: string, val: (MultiType | Symbol)[], opts?: T.TermsQuery): this { + terms (key: string, val: (MultiType | Symbol)[]): this + terms (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): this + terms (key: string, val: (MultiType | Symbol)[], opts?: any): this { this[kState].push(Q.terms(key, val, opts)) return this } @@ -200,42 +217,49 @@ class FluentQ { } must (...queries: FluentQ[]): this { - this[kState].push(Q.must(...queries.map(q => q.build()))) + // @ts-expect-error + this[kState].push(Q.must(...queries.flatMap(q => q[kState]))) return this } should (...queries: FluentQ[]): this { - this[kState].push(Q.should(...queries.map(q => q.build()))) + // @ts-expect-error + this[kState].push(Q.should(...queries.flatMap(q => q[kState]))) return this } mustNot (...queries: FluentQ[]): this { - this[kState].push(Q.mustNot(...queries.map(q => q.build()))) + // @ts-expect-error + this[kState].push(Q.mustNot(...queries.flatMap(q => q[kState]))) return this } filter (...queries: FluentQ[]): this { - this[kState].push(Q.filter(...queries.map(q => q.build()))) + // @ts-expect-error + this[kState].push(Q.filter(...queries.flatMap(q => q[kState]))) return this } bool (...queries: FluentQ[]): this { - this[kState].push(Q.bool(...queries.map(q => q.build()))) + // @ts-expect-error + this[kState].push(Q.bool(...queries.flatMap(q => q[kState]))) return this } - and (...queries: FluentQ[]): this { - this[kState].push(Q.and(...queries.map(q => q.build()))) + and (...blocks: FluentQ[]): this { + const { query = {}, ...searchRequest } = this.build() + this[kState] = [searchRequest, Q.and(query, ...blocks.map(q => q.buildQuery()))] return this } - or (...queries: FluentQ[]): this { - this[kState].push(Q.or(...queries.map(q => q.build()))) + or (...blocks: FluentQ[]): this { + const { query = {}, ...searchRequest } = this.build() + this[kState] = [searchRequest, Q.and(query, ...blocks.map(q => q.buildQuery()))] return this } not (query: FluentQ): this { - this[kState].push(Q.not(query.build())) + this[kState].push(Q.not(query.buildQuery())) return this } @@ -296,6 +320,16 @@ class FluentQ { this[kState].push(obj) return this } + + clone (): FluentQ { + const F = new FluentQ() + F[kState] = this[kState].slice() + return F + } + + toJSON () { + return this.build() + } } export default function build () { diff --git a/dsl/src/query.ts b/dsl/src/query.ts index c3a6e83f3..51d337183 100644 --- a/dsl/src/query.ts +++ b/dsl/src/query.ts @@ -40,7 +40,7 @@ type QueryBlock = { query: T.QueryContainer } type MultiType = string | number | boolean function Q (...blocks: (SearchRequest | T.QueryContainer | T.QueryContainer[] | BoolQuery)[]): SearchRequest { - blocks = blocks.flat() as (SearchRequest | T.QueryContainer | BoolQuery)[] + blocks = blocks.flat() const topLevelKeys = [ 'aggs', 'collapse', @@ -300,22 +300,24 @@ namespace Q { export function term (key: string, val: MultiType | Symbol): { term: Record } export function term (key: string, val: MultiType | Symbol, opts: T.TermQuery): { term: Record } - export function term (key: string, val: (MultiType | Symbol)[]): { terms: T.TermsQuery } - export function term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { terms: T.TermsQuery } + export function term (key: string, val: (MultiType | Symbol)[]): { terms: Record } + export function term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { term: Record }[] export function term (key: string, val: any, opts?: any): any { - if (Array.isArray(val)) { - return Q.terms(key, val, opts) + if (Array.isArray(val) && opts == null) { + return Q.terms(key, val) } return generateValueObject('term', key, val, opts) } - export function terms (key: string, val: (MultiType | Symbol)[], opts?: T.TermsQuery): { terms: T.TermsQuery } { - return { - terms: { - [key]: val, - ...opts + export function terms (key: string, val: (MultiType | Symbol)[]): { terms: Record } + export function terms (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { terms: Record } + export function terms (key: string, val: (MultiType | Symbol)[], opts?: any): any { + if (opts == null) { + return { + terms: { [key]: val } } } + return { terms: opts } } export function termsSet (key: string, val: (string | Symbol)[], opts?: T.TermsSetQuery): { terms_set: Record } {