Fixed minor bugs and improved fluent api

This commit is contained in:
delvedor
2020-09-14 17:13:34 +02:00
parent 70062550db
commit e932366caf
2 changed files with 61 additions and 25 deletions

View File

@ -29,6 +29,16 @@ import A from './aggregation'
import * as t from './types' import * as t from './types'
import T from '../es-types' import T from '../es-types'
type SearchRequest = Required<T.SearchRequest>['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') const kState = Symbol('dsl-query-state')
type MultiType = string | number | boolean type MultiType = string | number | boolean
@ -36,15 +46,20 @@ type MultiType = string | number | boolean
// and automatically call `query.build()` // and automatically call `query.build()`
class FluentQ { class FluentQ {
[kState]: Record<string, any>[] [kState]: (SearchRequest | T.QueryContainer | T.QueryContainer[] | BoolQuery)[]
constructor () { constructor () {
this[kState] = [] this[kState] = []
} }
build (): Record<string, any> { build (): SearchRequest {
return Q(...this[kState]) return Q(...this[kState])
} }
buildQuery (): T.QueryContainer {
const b = Q(...this[kState])
return b.query != null ? b.query : {}
}
param (key: string): Symbol { param (key: string): Symbol {
return Q.param(key) return Q.param(key)
} }
@ -123,14 +138,16 @@ class FluentQ {
term (key: string, val: (MultiType | Symbol)[]): this term (key: string, val: (MultiType | Symbol)[]): this
term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): this term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): this
term (key: string, val: any, opts?: any): this { term (key: string, val: any, opts?: any): this {
if (Array.isArray(val)) { if (Array.isArray(val) && opts == null) {
return this.terms(key, val, opts) return this.terms(key, val)
} }
this[kState].push(Q.term(key, val, opts)) this[kState].push(Q.term(key, val, opts))
return this 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)) this[kState].push(Q.terms(key, val, opts))
return this return this
} }
@ -200,42 +217,49 @@ class FluentQ {
} }
must (...queries: FluentQ[]): this { 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 return this
} }
should (...queries: FluentQ[]): 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 return this
} }
mustNot (...queries: FluentQ[]): 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 return this
} }
filter (...queries: FluentQ[]): 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 return this
} }
bool (...queries: FluentQ[]): 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 return this
} }
and (...queries: FluentQ[]): this { and (...blocks: FluentQ[]): this {
this[kState].push(Q.and(...queries.map(q => q.build()))) const { query = {}, ...searchRequest } = this.build()
this[kState] = [searchRequest, Q.and(query, ...blocks.map(q => q.buildQuery()))]
return this return this
} }
or (...queries: FluentQ[]): this { or (...blocks: FluentQ[]): this {
this[kState].push(Q.or(...queries.map(q => q.build()))) const { query = {}, ...searchRequest } = this.build()
this[kState] = [searchRequest, Q.and(query, ...blocks.map(q => q.buildQuery()))]
return this return this
} }
not (query: FluentQ): this { not (query: FluentQ): this {
this[kState].push(Q.not(query.build())) this[kState].push(Q.not(query.buildQuery()))
return this return this
} }
@ -296,6 +320,16 @@ class FluentQ {
this[kState].push(obj) this[kState].push(obj)
return this return this
} }
clone (): FluentQ {
const F = new FluentQ()
F[kState] = this[kState].slice()
return F
}
toJSON () {
return this.build()
}
} }
export default function build () { export default function build () {

View File

@ -40,7 +40,7 @@ type QueryBlock = { query: T.QueryContainer }
type MultiType = string | number | boolean type MultiType = string | number | boolean
function Q (...blocks: (SearchRequest | T.QueryContainer | T.QueryContainer[] | BoolQuery)[]): SearchRequest { function Q (...blocks: (SearchRequest | T.QueryContainer | T.QueryContainer[] | BoolQuery)[]): SearchRequest {
blocks = blocks.flat() as (SearchRequest | T.QueryContainer | BoolQuery)[] blocks = blocks.flat()
const topLevelKeys = [ const topLevelKeys = [
'aggs', 'aggs',
'collapse', 'collapse',
@ -300,22 +300,24 @@ namespace Q {
export function term (key: string, val: MultiType | Symbol): { term: Record<string, MultiType> } export function term (key: string, val: MultiType | Symbol): { term: Record<string, MultiType> }
export function term (key: string, val: MultiType | Symbol, opts: T.TermQuery): { term: Record<string, T.TermQuery> } export function term (key: string, val: MultiType | Symbol, opts: T.TermQuery): { term: Record<string, T.TermQuery> }
export function term (key: string, val: (MultiType | Symbol)[]): { terms: T.TermsQuery } export function term (key: string, val: (MultiType | Symbol)[]): { terms: Record<string, string[]> }
export function term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { terms: T.TermsQuery } export function term (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { term: Record<string, T.TermQuery> }[]
export function term (key: string, val: any, opts?: any): any { export function term (key: string, val: any, opts?: any): any {
if (Array.isArray(val)) { if (Array.isArray(val) && opts == null) {
return Q.terms(key, val, opts) return Q.terms(key, val)
} }
return generateValueObject('term', key, val, opts) return generateValueObject('term', key, val, opts)
} }
export function terms (key: string, val: (MultiType | Symbol)[], opts?: T.TermsQuery): { terms: T.TermsQuery } { export function terms (key: string, val: (MultiType | Symbol)[]): { terms: Record<string, string[]> }
return { export function terms (key: string, val: (MultiType | Symbol)[], opts: T.TermsQuery): { terms: Record<string, T.TermsQuery> }
terms: { export function terms (key: string, val: (MultiType | Symbol)[], opts?: any): any {
[key]: val, if (opts == null) {
...opts return {
terms: { [key]: val }
} }
} }
return { terms: opts }
} }
export function termsSet (key: string, val: (string | Symbol)[], opts?: T.TermsSetQuery): { terms_set: Record<string, T.TermsSetQuery> } { export function termsSet (key: string, val: (string | Symbol)[], opts?: T.TermsSetQuery): { terms_set: Record<string, T.TermsSetQuery> } {