Socket
Socket
Sign inDemoInstall

elasticmagic

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

elasticmagic - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

83

dist/agg.d.ts

@@ -1,10 +0,13 @@

import { ParamsExpression, ParamsType, Params, Expression } from "./expression";
import { Field, FieldType } from "./document";
import { Agg, Dictionary } from "./types";
import { DocClass, Field, FieldType } from './document';
import { Expression, Params, ParamsExpression, ParamsType } from './expression';
import { InstanceMapper } from './query';
import { Dictionary, RawAgg, RawAggBucket } from './types';
declare type BucketKey = string | number;
declare class Bucket {
private parent;
key: any;
key: BucketKey;
docCount: number;
aggregations: Dictionary<string, AggResult>;
constructor(rawData: any, aggExpr: BucketAgg, parent: any, docClsMap: any, mapperRegistry: any);
constructor(rawData: RawAggBucket, aggExpr: BucketAgg, parent: AggResult, // TODO used by self.parent._populate_instances()
docClsMap: Dictionary<string, DocClass>, mapperRegistry: any);
getAggregation(name: string): AggResult;

@@ -20,45 +23,53 @@ toString(): string;

export declare class AggExpression extends ParamsExpression {
_visitName: string;
_aggName: any;
buildAggResult(rawData: any, docClsMap?: any, mapperRegistry?: any): void;
visitName: string;
aggName: any;
buildAggResult(rawData: Dictionary<string, any>, docClsMap?: Dictionary<string, DocClass>, mapperRegistry?: any): AggResult;
}
export declare class BucketAgg extends AggExpression {
private resultClass;
_visitName: string;
_aggName: any;
_aggregations: Params;
constructor(aggs: any, params: ParamsType, resultClass: any);
buildAggResult(rawData: Agg, docClsMap?: any, mapperRegistry?: any): AggResult;
visitName: string;
aggName: string;
aggregations: Params;
constructor(aggs?: Dictionary<string, Filter>, params?: ParamsType);
}
declare class SingleBucketAggResult extends AggResult {
docCount: number;
aggregations: Dictionary<string, AggResult>;
constructor(aggExpr: SingleBucketAgg, // TODO maybe later we will need to pass wider type
rawData: RawAggBucket, docClsMap: Dictionary<string, DocClass>, mapperRegistry: any);
getAggregation(name: string): AggResult;
}
export declare class MultiBucketAggResult extends AggResult {
private instanceMapper;
private instanceMapper?;
private bucketClass;
buckets: any;
buckets: Bucket[];
private bucketsMap;
private mapperRegistry;
constructor(aggExpr: BucketAgg, rawData: any, docClsMap: any, mapperRegistry: any, instanceMapper: any);
addBucket(bucket: any): void;
getBucket(key: any): any;
constructor(aggExpr: MultiBucketAgg, rawData: RawAgg, docClsMap: Dictionary<string, DocClass>, mapperRegistry: any, instanceMapper?: InstanceMapper<any, any> | undefined);
addBucket(bucket: Bucket): void;
getBucket(key: BucketKey): Bucket;
}
export declare class SingleBucketAgg extends BucketAgg {
_aggName: any;
constructor(aggs: any, params: any);
aggName: string;
constructor(aggs?: Dictionary<string, Filter>, params?: Dictionary<string, any>);
buildAggResult(rawData: RawAggBucket, docClsMap?: Dictionary<string, DocClass>, mapperRegistry?: any): SingleBucketAggResult;
}
export declare class MultiBucketAgg extends BucketAgg {
private type?;
protected instanceMapper?: any;
_aggName: any;
constructor(aggs: any, params: TermsOptionsShrink, // TODO probably not appropriate type as MultiBucketAgg is parent class, replace with more generic
type?: FieldType | undefined, instanceMapper?: any);
buildAggResult(rawData: any, docClsMap?: any, mapperRegistry?: any): MultiBucketAggResult;
protected instanceMapper?: InstanceMapper<any, any> | undefined;
aggName: any;
constructor(aggs?: Dictionary<string, Filter>,
/**
* TODO probably not appropriate type as MultiBucketAgg is parent class, replace with more generic
*/
params?: TermsOptionsShrink, type?: FieldType | undefined, // TODO used by def clone
instanceMapper?: InstanceMapper<any, any> | undefined);
buildAggResult(rawData: RawAgg, docClsMap?: Dictionary<string, DocClass>, mapperRegistry?: any): MultiBucketAggResult;
}
declare type TermsOptions = {
field?: Field;
field: Field;
script?: any;
size?: number;
type?: FieldType;
aggs?: {
[agg: string]: Filter;
};
instanceMapper?: any;
aggs?: Dictionary<string, Filter>;
instanceMapper?: InstanceMapper<any, any>;
};

@@ -71,3 +82,3 @@ declare type TermsOptionsShrink = {

export declare class Terms extends MultiBucketAgg {
_aggName: string;
aggName: string;
constructor({ field, type, aggs, instanceMapper, ...opts }: TermsOptions);

@@ -77,9 +88,7 @@ }

filter: Expression;
aggs?: {
[agg: string]: Filter;
};
aggs?: Dictionary<string, Filter>;
};
export declare class Filter extends SingleBucketAgg {
_visitName: string;
_aggName: string;
visitName: string;
aggName: string;
filter: Expression;

@@ -86,0 +95,0 @@ constructor({ filter, aggs, ...opts }: FilterOptions);

@@ -17,3 +17,4 @@ "use strict";

class Bucket {
constructor(rawData, aggExpr, parent, docClsMap, mapperRegistry) {
constructor(rawData, aggExpr, parent, // TODO used by self.parent._populate_instances()
docClsMap, mapperRegistry) {
this.parent = parent;

@@ -23,7 +24,6 @@ this.aggregations = {};

this.docCount = rawData.doc_count;
aggExpr._aggregations.getParamsKvList().forEach((agg) => {
aggExpr.aggregations.getParamsKvList().forEach((agg) => {
const aggName = agg[0];
const aggExpr = agg[1];
this.aggregations[aggName] = aggExpr.buildAggResult(rawData[aggName], docClsMap, mapperRegistry);
;
const expr = agg[1];
this.aggregations[aggName] = expr.buildAggResult(rawData[aggName], docClsMap, mapperRegistry);
});

@@ -49,5 +49,5 @@ }

super(...arguments);
this._visitName = 'agg';
this.visitName = 'agg';
}
buildAggResult(rawData, docClsMap = null, mapperRegistry = null) {
buildAggResult(rawData, docClsMap = {}, mapperRegistry = {}) {
throw new Error('AggExpression: buildAggResult not implemented');

@@ -58,13 +58,7 @@ }

class BucketAgg extends AggExpression {
// TODO here must be interfact for resultClass, but in typescript it is hard to reason abount how to do this properly
constructor(aggs, params, resultClass) {
constructor(aggs, params) {
super(params);
this.resultClass = resultClass;
this._visitName = 'bucketAgg';
// TODO kwargs.pop('aggregations', {})
this._aggregations = new expression_1.Params(aggs);
this.visitName = 'bucketAgg';
this.aggregations = new expression_1.Params(aggs);
}
buildAggResult(rawData, docClsMap = null, mapperRegistry = null) {
return new this.resultClass(this, rawData, docClsMap, mapperRegistry);
}
}

@@ -80,17 +74,12 @@ exports.BucketAgg = BucketAgg;

class SingleBucketAggResult extends AggResult {
constructor(aggExpr, rawData, docClsMap, mapperRegistry, instanceMapper) {
constructor(aggExpr, // TODO maybe later we will need to pass wider type
rawData, docClsMap, mapperRegistry) {
super(aggExpr);
this.instanceMapper = instanceMapper;
this.bucketClass = Bucket;
this.bucketsMap = {};
this.mapperRegistry = {};
this.buckets = [];
this.docCount = 0;
this.aggregations = {};
this.docCount = rawData.doc_count;
aggExpr._aggregations.getParamsKvList().forEach((agg) => {
aggExpr.aggregations.getParamsKvList().forEach((agg) => {
const aggName = agg[0];
const aggExpr = agg[1];
this.aggregations[aggName] = aggExpr.buildAggResult(rawData[aggName], docClsMap, mapperRegistry);
;
const expr = agg[1];
this.aggregations[aggName] = expr.buildAggResult(rawData[aggName], docClsMap, mapperRegistry);
});

@@ -128,2 +117,3 @@ }

if (this.instanceMapper) {
// TOOD this piece of code is broken, as mapperRegistry must use sring as key, not instanceMapper itself
if (!(this.instanceMapper in this.mapperRegistry)) {

@@ -148,14 +138,23 @@ this.mapperRegistry[this.mapperRegistry] = [];

constructor(aggs, params) {
super(aggs, params, SingleBucketAggResult);
super(aggs, params);
}
// TODO in python we just pass resultcls and parent call buildAggResult
// but for any reason we do not do this right now, maybe we will do this later
buildAggResult(rawData, docClsMap = {}, mapperRegistry = null) {
return new SingleBucketAggResult(this, rawData, docClsMap, mapperRegistry);
}
}
exports.SingleBucketAgg = SingleBucketAgg;
class MultiBucketAgg extends BucketAgg {
constructor(aggs, params, // TODO probably not appropriate type as MultiBucketAgg is parent class, replace with more generic
type, instanceMapper) {
super(aggs, params, MultiBucketAggResult);
constructor(aggs,
/**
* TODO probably not appropriate type as MultiBucketAgg is parent class, replace with more generic
*/
params, type, // TODO used by def clone
instanceMapper) {
super(aggs, params);
this.type = type;
this.instanceMapper = instanceMapper;
}
buildAggResult(rawData, docClsMap = null, mapperRegistry = null) {
buildAggResult(rawData, docClsMap = {}, mapperRegistry = null) {
return new MultiBucketAggResult(this, rawData, docClsMap, mapperRegistry, this.instanceMapper);

@@ -165,11 +164,11 @@ }

exports.MultiBucketAgg = MultiBucketAgg;
function getType(type, field) {
return type || (field ? field.getType() : null);
function getType(field, type) {
var _a, _b;
return type || (_b = (_a = field) === null || _a === void 0 ? void 0 : _a.getType(), (_b !== null && _b !== void 0 ? _b : null));
}
;
class Terms extends MultiBucketAgg {
constructor(_a) {
var { field, type, aggs, instanceMapper } = _a, opts = __rest(_a, ["field", "type", "aggs", "instanceMapper"]);
super(aggs, Object.assign({ field }, opts), getType(type, field), instanceMapper);
this._aggName = 'terms';
super(aggs, Object.assign({ field }, opts), getType(field, type), instanceMapper);
this.aggName = 'terms';
this.instanceMapper = instanceMapper;

@@ -183,4 +182,4 @@ }

super(aggs, opts);
this._visitName = 'filterAgg';
this._aggName = 'filter';
this.visitName = 'filterAgg';
this.aggName = 'filter';
this.filter = filter;

@@ -187,0 +186,0 @@ }

@@ -1,5 +0,6 @@

import { Client } from "@elastic/elasticsearch";
import { SearchQuery, SearchQueryOptions } from "./query";
import { SearchResult } from "./result";
import { Doc } from "./document";
import { Client } from '@elastic/elasticsearch';
import { Doc } from './document';
import { SearchQuery, SearchQueryOptions } from './query';
import { SearchResult } from './result';
import { Nullable } from './types';
export declare class Index {

@@ -21,7 +22,8 @@ private name;

private client;
private index;
private index?;
private esVersion?;
constructor(client: Client, indexName: string);
searchQuery(searchQueryOptions: SearchQueryOptions): SearchQuery;
getIndex(): Index;
constructor(client: Client, indexName?: string);
searchQuery(searchQueryOptions?: SearchQueryOptions): SearchQuery;
getIndex(): Nullable<Index>;
addIndex(name: string): void;
getEsVersion(): Promise<EsVersion>;

@@ -31,4 +33,2 @@ private processEsVersionResult;

* Make a request using underlying es client.
*
* NOTE: If you want to type response body, pass a generic type.
* @param compiledQuery

@@ -41,3 +41,2 @@ * @param params

*
* NOTE: If you want to type response body, pass a generic type.
* @param rawResultBody \

@@ -51,4 +50,4 @@ * @param searchQueryContext

*/
search<T extends Doc, TRaw>(searchQuery: SearchQuery): Promise<SearchResult<T>>;
search<T extends Doc>(searchQuery: SearchQuery): Promise<SearchResult<T>>;
}
export {};

@@ -36,3 +36,2 @@ "use strict";

}
;
}

@@ -42,5 +41,7 @@ class Cluster {

this.client = client;
this.index = new Index(indexName, this);
if (indexName) {
this.index = new Index(indexName, this);
}
}
searchQuery(searchQueryOptions) {
searchQuery(searchQueryOptions = {}) {
return new query_1.SearchQuery(Object.assign({ cluster: this, index: this.index }, searchQueryOptions));

@@ -51,6 +52,10 @@ }

}
addIndex(name) {
this.index = new Index(name, this);
}
getEsVersion() {
return __awaiter(this, void 0, void 0, function* () {
if (this.esVersion)
if (this.esVersion) {
return this.esVersion;
}
const rawResult = yield this.client.info();

@@ -68,4 +73,2 @@ return this.processEsVersionResult(rawResult.body);

* Make a request using underlying es client.
*
* NOTE: If you want to type response body, pass a generic type.
* @param compiledQuery

@@ -78,3 +81,6 @@ * @param params

// TODO get client method to call, must be a accep-like function in searchQuery
return this.client.search(Object.assign({ index: this.index.getName(), body: compiledQuery }, params));
if (!this.index) {
throw new Error('index required');
}
return this.client.search(Object.assign({ body: compiledQuery, index: this.index.getName() }, params));
});

@@ -85,3 +91,2 @@ }

*
* NOTE: If you want to type response body, pass a generic type.
* @param rawResultBody \

@@ -91,5 +96,4 @@ * @param searchQueryContext

processResult(rawResultBody, searchQueryContext) {
return new result_1.SearchResult(rawResultBody, searchQueryContext.aggregations, searchQueryContext.docClass, searchQueryContext.instanceMapper);
return new result_1.SearchResult(rawResultBody, searchQueryContext.aggregations, searchQueryContext.docClasses, searchQueryContext.instanceMapper);
}
;
/**

@@ -96,0 +100,0 @@ * run search query against elasticsearch cluster and return processed result.

@@ -1,2 +0,4 @@

import { SearchQueryContext, Query } from "./query";
import { Field } from './document';
import { Query, SearchQueryContext } from './query';
export declare function isField(x: any): x is Field;
export declare class CompilerVisitor {

@@ -9,13 +11,7 @@ params: Query;

/**
* This is where we start and finish building our query (doc must be rewrited)
* This is where we start building our query
* @param queryContext
*/
private visitSearchQueryContext;
/**
* @param expression
*/
private visitQueryExpression;
/**
* @param expression
*/
private visitFieldQuery;

@@ -33,2 +29,4 @@ private visitTerm;

private visitRange;
private visitSort;
private visitSource;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const document_1 = require("./document");
const expression_1 = require("./expression");
const util_1 = require("./util");
// TODO can not move to utils due to cirular inports
function isField(x) {
return x instanceof document_1.Field;
}
exports.isField = isField;
class CompilerVisitor {

@@ -15,6 +21,6 @@ constructor() {

let visitName;
if ((_a = expression) === null || _a === void 0 ? void 0 : _a._visitName) {
visitName = expression._visitName;
if ((_a = expression) === null || _a === void 0 ? void 0 : _a.visitName) {
visitName = expression.visitName;
}
// visitName must be constant
// TODO visitName must be constant
switch (visitName) {

@@ -27,5 +33,2 @@ case 'searchQueryContext':

return this.visitParams(expression);
case 'fieldExpression':
console.log('in python it is not implemented');
return;
case 'fieldQuery':

@@ -49,2 +52,6 @@ return this.visitFieldQuery(expression);

return this.visitRange(expression);
case 'sort':
return this.visitSort(expression);
case 'source':
return this.visitSource(expression);
default:

@@ -55,13 +62,9 @@ }

}
// if this is object
if (util_1.isObject(expression)) {
return this.visitObject(expression);
}
// return as is, mostly for simple types
return expression;
}
getQuery(queryContext) {
const q = queryContext.query;
// TODO if wrap_function_score:
return q;
return queryContext.query;
}

@@ -74,7 +77,6 @@ getFilteredQuery(queryContext) {

}
// TODO(for es > 6) if not features.supports_mapping_types and doc_classes:
if (filterClauses.length > 0) {
// features.supports_bool_filter is always true for es > 2
if (filterClauses.length === 1) {
return new expression_1.Bool({ must: q, filter: filterClauses[0] });
const clause = filterClauses[0];
return new expression_1.Bool({ must: q, filter: clause });
}

@@ -86,3 +88,3 @@ return new expression_1.Bool({ must: q, filter: filterClauses });

/**
* This is where we start and finish building our query (doc must be rewrited)
* This is where we start building our query
* @param queryContext

@@ -96,6 +98,8 @@ */

}
// TODO order_by (sort)
if (queryContext.source != null && queryContext !== undefined) {
params._source = queryContext.source;
if (queryContext.sort.length > 0) {
params.sort = this.visit(queryContext.sort);
}
if (!util_1.isNullOrUndef(queryContext.source)) {
params._source = this.visit(queryContext.source);
}
if (queryContext.limit !== null) {

@@ -109,37 +113,25 @@ params.size = queryContext.limit;

}
/**
* @param expression
*/
// TODO return type
visitQueryExpression(expression) {
return {
[expression._queryName]: this.visit(expression.params)
[expression.queryName]: this.visit(expression.params),
};
}
/**
* @param expression
*/
// TODO return type
visitFieldQuery(expression) {
// const exprParams = new Params(expression.params);
const exprParams = expression.params;
if (exprParams.length > 0) { // TODO maybe implement iterator for Params
let params = { [expression._queryKey]: this.visit(expression.query) };
params = Object.assign(Object.assign({}, params), exprParams); // TODo here can be broken line
if (exprParams.length > 0) {
let params = { [expression.queryKey]: this.visit(expression.query) };
params = Object.assign(Object.assign({}, params), exprParams);
return {
[expression._queryName]: {
[this.visit(expression.field)]: params
}
[expression.queryName]: {
[this.visit(expression.field)]: params,
},
};
}
return {
[expression._queryName]: {
[this.visit(expression.field)]: this.visit(expression.query)
}
[expression.queryName]: {
[this.visit(expression.field)]: this.visit(expression.query),
},
};
}
visitTerm(term) {
// TODO in python there is a visit call to field type but we do not have it yet
// const fieldName = term.field;
// TODO if field_name == '_id':
return this.visitFieldQuery(term);

@@ -149,6 +141,5 @@ }

const fieldName = this.visit(expression.field);
let params = { [fieldName]: this.visit(expression.terms) };
params = Object.assign(Object.assign({}, params), this.visit(expression.params)); // { company_id: [123] }
const params = { [fieldName]: this.visit(expression.terms) };
return {
'terms': params
terms: Object.assign(Object.assign({}, params), this.visit(expression.params)),
};

@@ -180,3 +171,3 @@ }

return {
[agg._aggName]: this.visit(agg.params)
[agg.aggName]: this.visit(agg.params),
};

@@ -186,6 +177,6 @@ }

const params = {
[agg._aggName]: this.visit(agg.params),
[agg.aggName]: this.visit(agg.params),
};
if (agg._aggregations.length > 0) {
params.aggregations = this.visit(agg._aggregations);
if (agg.aggregations.length > 0) {
params.aggregations = this.visit(agg.aggregations);
}

@@ -196,3 +187,3 @@ return params;

const params = this.visitBucketAgg(agg);
params[agg._aggName] = this.visit(agg.filter);
params[agg.aggName] = this.visit(agg.filter);
return params;

@@ -202,9 +193,53 @@ }

const fieldParams = {
[this.visit(expr.field)]: this.visit(expr.params)
[this.visit(expr.field)]: this.visit(expr.params),
};
return {
range: Object.assign(Object.assign({}, this.visit(expr.rangeParams)), fieldParams)
range: Object.assign(Object.assign({}, this.visit(expr.rangeParams)), fieldParams),
};
}
visitSort(expr) {
if (expr.params.length) {
const params = Object.assign({ order: this.visit(expr.order) }, this.visit(expr.params));
return {
[this.visit(expr.field)]: params,
};
}
else if (expr.order) {
return {
[this.visit(expr.field)]: this.visit(expr.order),
};
}
return this.visit(expr.field);
}
visitSource(expr) {
var _a, _b;
if (expr.include || expr.exclude) {
const params = {};
if ((_a = expr.exclude) === null || _a === void 0 ? void 0 : _a.length) {
const exclude = this.visit(expr.exclude);
if (exclude.length) {
params.exclude = exclude;
}
}
if ((_b = expr.include) === null || _b === void 0 ? void 0 : _b.length) {
const include = this.visit(expr.include);
if (include.length) {
params.include = include;
}
}
return params;
}
if (util_1.isBoolean(expr.fields)) {
return expr.fields;
}
if (util_1.isString(expr.fields)) {
return expr.fields;
}
if (isField(expr.fields)) {
return this.visit(expr.fields);
}
const fields = expr.fields;
return fields.map((field) => this.visit(field));
}
}
exports.CompilerVisitor = CompilerVisitor;

@@ -1,4 +0,4 @@

import { Terms, Term, Bool, Expression, TermValue, RangeExpr, RangeValue } from "./expression";
import { SearchResult } from "./result";
import { Hit } from "./types";
import { Bool, Expression, RangeExpr, RangeValue, Sort, SortOpts, Term, Terms, TermValue } from './expression';
import { SearchResult } from './result';
import { Hit } from './types';
export declare class FieldType {

@@ -12,15 +12,23 @@ }

}
export declare type FieldOpts = {
name?: string;
parent?: DocClass;
};
export declare class Field extends Expression {
private type;
name: string;
readonly _visitName = "field";
constructor(type: FieldType, name: string);
in_(terms: TermValue[]): Terms;
not_(term: TermValue): Bool;
eq_(other: TermValue): Term;
lt_(other: RangeValue): RangeExpr;
gt_(other: RangeValue): RangeExpr;
lte_(other: RangeValue): RangeExpr;
gte_(other: RangeValue): RangeExpr;
readonly name: string;
readonly parent: DocClass;
readonly visitName = "field";
constructor(type: FieldType, name: string, parent: DocClass);
in(terms: TermValue[]): Terms;
not(term: TermValue): Bool;
eq(other: TermValue): Term;
lt(other: RangeValue): RangeExpr;
gt(other: RangeValue): RangeExpr;
lte(other: RangeValue): RangeExpr;
gte(other: RangeValue): RangeExpr;
asc(opts?: SortOpts): Sort;
desc(opts?: SortOpts): Sort;
getType(): FieldType;
collectDocClasses(): Readonly<DocClass[]>;
}

@@ -31,18 +39,12 @@ declare type DocOpts = {

};
export interface IDocument {
_docType: string;
new (opts: DocOpts): Doc;
}
export declare class Doc {
static readonly _docType: string;
private hit;
private result;
_id: string | number;
static readonly docType: string;
protected hit: Hit;
protected result: SearchResult<any>;
_id: string;
constructor(opts: DocOpts);
/**
* If instanceMapper was defined for query then return instance mapped by instanceMapper
* else return null;
*/
get instance(): any | null;
static getDocCls(): string;
private populateFromSource;
}
export declare type DocClass = typeof Doc;
export {};

@@ -17,37 +17,45 @@ "use strict";

class Field extends expression_1.Expression {
constructor(type, name) {
constructor(type, name, parent) {
super();
this.type = type;
this.name = name;
this._visitName = 'field';
this.parent = parent;
this.visitName = 'field';
}
in_(terms) {
in(terms) {
return new expression_1.Terms(this, terms);
}
not_(term) {
not(term) {
return expression_1.Bool.mustNot(new expression_1.Term(this, term));
}
eq_(other) {
// TODO add if other is None: return self.missing()
eq(other) {
// TODO add if other is None: return self.missing()
return new expression_1.Term(this, other);
}
lt_(other) {
lt(other) {
return new expression_1.RangeExpr(this, { lt: other });
}
gt_(other) {
gt(other) {
return new expression_1.RangeExpr(this, { gt: other });
}
lte_(other) {
lte(other) {
return new expression_1.RangeExpr(this, { lte: other });
}
gte_(other) {
gte(other) {
return new expression_1.RangeExpr(this, { gte: other });
}
asc(opts) {
return new expression_1.Sort(this, 'asc', opts);
}
desc(opts) {
return new expression_1.Sort(this, 'desc', opts);
}
getType() {
return this.type;
}
collectDocClasses() {
return this.parent ? [this.parent] : [];
}
}
exports.Field = Field;
// TODO maybe decorator can be used as an alternative to metaclass
// https://github.com/Microsoft/TypeScript/issues/17454
class Doc {

@@ -58,12 +66,18 @@ constructor(opts) {

this._id = opts.hit._id;
if (this.hit._source) {
this.populateFromSource();
}
}
;
/**
* If instanceMapper was defined for query then return instance mapped by instanceMapper
* else return null;
*/
get instance() {
return null;
static getDocCls() {
return this.docType;
}
populateFromSource() {
Object.entries(this.hit._source).forEach((hitKV) => {
const fieldName = hitKV[0];
const fieldValue = hitKV[1];
const _this = this; // TODO well you should't see this
_this[fieldName] = fieldValue;
});
}
}
exports.Doc = Doc;

@@ -1,31 +0,21 @@

import { Field } from "./document";
import { DocClass, Field } from './document';
import { Dictionary, Nullable } from './types';
export declare type TermValue = number | string | boolean;
export declare type TermField = {
[field: string]: TermValue;
};
export declare type TermField = Dictionary<string, TermValue>;
export declare class Expression {
readonly _visitName: string;
readonly _queryName: string;
readonly _queryKey: string;
readonly visitName: string;
readonly queryName: string;
readonly queryKey: string;
collectDocClasses(): Readonly<DocClass[]>;
}
declare type BoolOptions = {
must?: any;
filter?: any;
must_not?: any;
should?: any;
mininum_should_match?: any;
boost?: any;
disable_coord?: any;
};
export declare type ParamsType = {
[key: string]: any;
};
export declare type ParamsType = Dictionary<any, any>;
export declare type ParamKV = [string, any];
export declare class Params extends Expression {
_visitName: string;
visitName: string;
private params;
private paramsKvList;
constructor(params?: ParamsType);
getParamsKvList(): Array<ParamKV>;
constructor(params?: Nullable<ParamsType>);
getParamsKvList(): ParamKV[];
getParams(): ParamsType;
collectDocClasses(): Readonly<DocClass[]>;
get length(): number;

@@ -35,3 +25,3 @@ }

obj: any;
_visitName: string;
visitName: string;
constructor(obj: any);

@@ -41,25 +31,36 @@ }

params: Params;
constructor(params: any);
constructor(params?: Dictionary<any, any>);
collectDocClasses(): Readonly<DocClass[]>;
}
export declare type SourceField = boolean | string | Field | null;
export declare class Source extends Expression {
fields: boolean | string | Field | Array<string | Field>;
include?: (string | Field)[] | undefined;
exclude?: (string | Field)[] | undefined;
visitName: string;
constructor(fields: boolean | string | Field | Array<string | Field>, include?: (string | Field)[] | undefined, exclude?: (string | Field)[] | undefined);
collectDocClasses(): Readonly<DocClass[]>;
}
export declare class QueryExpression extends ParamsExpression {
_visitName: string;
visitName: string;
}
export declare class FieldExpression extends QueryExpression {
_visitName: string;
field: Expression;
constructor(field: Field, params: any);
private wrapLiteral;
field: Field;
visitName: string;
constructor(field: Field, params?: Dictionary<any, any>);
collectDocClasses(): Readonly<DocClass[]>;
}
export declare type FieldQueryValue = string | number | boolean | null;
export declare class FieldQueryExpression extends FieldExpression {
query: any;
_visitName: string;
_queryKey: string;
constructor(field: Field, query: any);
query: FieldQueryValue;
visitName: string;
queryKey: string;
constructor(field: Field, query: FieldQueryValue);
collectDocClasses(): Readonly<DocClass[]>;
}
export declare class Term extends FieldQueryExpression {
_visitName: string;
_queryName: string;
_queryKey: string;
constructor(field: Field, // TODO possibly a cyclic import
term: TermValue);
visitName: string;
queryName: string;
queryKey: string;
constructor(field: Field, term: TermValue);
}

@@ -72,6 +73,7 @@ declare type TermsOptions = {

terms: TermValue[];
_visitName: string;
visitName: string;
constructor(field: Field, terms: TermValue[], termsOptions?: TermsOptions);
}
export declare type RangeValue = number | string | Date;
declare type ISOString = string;
export declare type RangeValue = number | string | Date | ISOString;
declare type RangeOptions = {

@@ -84,4 +86,4 @@ gte?: RangeValue;

to?: RangeValue;
includeLower?: boolean;
includeUpper?: boolean;
include_lower?: boolean;
include_upper?: boolean;
};

@@ -95,8 +97,17 @@ declare type RangeSettings = {

export declare class RangeExpr extends FieldExpression {
_visitName: string;
visitName: string;
rangeParams: Params;
constructor(field: Field, rangeOpts: RangeOptions, rangeSettings?: RangeSettings);
}
declare type BoolOptions = {
must?: Nullable<Expression[]>;
filter?: Nullable<Expression[]> | Expression;
must_not?: Nullable<Expression[]>;
should?: Nullable<Expression[]>;
mininum_should_match?: any;
boost?: any;
disable_coord?: any;
};
export declare class Bool extends QueryExpression {
_queryName: string;
queryName: string;
constructor(options: BoolOptions);

@@ -107,2 +118,16 @@ static must(...expressions: Expression[]): Expression;

}
export declare type SortOpts = {
mode?: any;
missing?: any;
nested_path?: any;
nested_filter?: any;
ignore_unmapped?: any;
};
export declare class Sort extends QueryExpression {
field: Field;
order: 'asc' | 'desc';
visitName: string;
constructor(field: Field, order: 'asc' | 'desc', opts?: SortOpts);
collectDocClasses(): Readonly<DocClass[]>;
}
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("./util");
// TODo this must be interface ???
// TODO make Expression an interface
class Expression {
constructor() {
this._visitName = 'notDefined_visitName';
this._queryName = 'notDefined_queryName';
this._queryKey = 'notDefined_queryKey';
collectDocClasses() {
return [];
}

@@ -14,6 +12,6 @@ }

class Params extends Expression {
// private pointer = 0;
constructor(params) {
super();
this._visitName = 'params';
this.visitName = 'params';
this.params = {}; // TODO maybe change this to Map
this.params = util_1.cleanParams(params);

@@ -28,2 +26,5 @@ this.paramsKvList = this.params ? Object.entries(this.params) : [];

}
collectDocClasses() {
return util_1.collectDocClasses(this.params);
}
get length() {

@@ -38,3 +39,3 @@ return this.paramsKvList.length;

this.obj = obj;
this._visitName = 'literal';
this.visitName = 'literal';
}

@@ -48,8 +49,26 @@ }

}
collectDocClasses() {
return util_1.collectDocClasses(this.params);
}
}
exports.ParamsExpression = ParamsExpression;
class Source extends Expression {
constructor(fields, include, exclude) {
super();
this.fields = fields;
this.include = include;
this.exclude = exclude;
this.visitName = 'source';
}
collectDocClasses() {
return util_1.uniqueArray(util_1.collectDocClasses(this.fields)
.concat(util_1.collectDocClasses(this.include))
.concat(util_1.collectDocClasses(this.exclude)));
}
}
exports.Source = Source;
class QueryExpression extends ParamsExpression {
constructor() {
super(...arguments);
this._visitName = 'queryExpression';
this.visitName = 'queryExpression';
}

@@ -59,13 +78,9 @@ }

class FieldExpression extends QueryExpression {
// TODO field is an AttributeField, OrderedAttributes
constructor(field, params) {
super(params); // TODO pass null or field ???
this._visitName = 'fieldExpression';
this.field = this.wrapLiteral(field);
super(params);
this.field = field;
this.visitName = 'fieldExpression';
}
wrapLiteral(field) {
if (field instanceof Expression) {
return field;
}
return new Literal(field);
collectDocClasses() {
return util_1.uniqueArray(super.collectDocClasses().concat(util_1.collectDocClasses(this.field)));
}

@@ -76,17 +91,20 @@ }

constructor(field, query) {
super(field, null);
super(field, {});
this.query = query;
this._visitName = 'fieldQuery';
this._queryKey = 'query';
this.visitName = 'fieldQuery';
this.queryKey = 'query';
}
collectDocClasses() {
const parentClasses = super.collectDocClasses();
const ownClasses = util_1.collectDocClasses(this.query);
return util_1.uniqueArray(parentClasses.concat(ownClasses));
}
}
exports.FieldQueryExpression = FieldQueryExpression;
class Term extends FieldQueryExpression {
constructor(field, // TODO possibly a cyclic import
term // value
) {
constructor(field, term) {
super(field, term);
this._visitName = 'term';
this._queryName = 'term';
this._queryKey = 'value';
this.visitName = 'term';
this.queryName = 'term';
this.queryKey = 'value';
}

@@ -99,3 +117,3 @@ }

this.terms = terms;
this._visitName = 'terms';
this.visitName = 'terms';
}

@@ -107,3 +125,3 @@ }

super(field, rangeOpts);
this._visitName = 'range';
this.visitName = 'range';
this.rangeParams = new Params();

@@ -117,5 +135,4 @@ this.rangeParams = new Params(rangeSettings);

super(options);
this._queryName = 'bool';
this.queryName = 'bool';
}
// TODO make it clear what Expression to return
static must(...expressions) {

@@ -138,2 +155,14 @@ if (expressions.length === 1) {

exports.Bool = Bool;
class Sort extends QueryExpression {
constructor(field, order, opts) {
super(opts);
this.field = field;
this.order = order;
this.visitName = 'sort';
}
collectDocClasses() {
return util_1.uniqueArray(super.collectDocClasses().concat(util_1.collectDocClasses(this.field)));
}
}
exports.Sort = Sort;
// TODO add Exists, Missing, Limit, Sort, Not, Ids, Script, Match, HasChild, HasParent
import { Cluster, Index } from './cluster';
import { Doc, Field, IntegerType, BooleanType, DateType } from './document';
import { BooleanType, DateType, Doc, Field, IntegerType } from './document';
import { Bool, RangeExpr, Term, Terms } from './expression';
import { SearchQuery } from './query';
import { Bool, RangeExpr, Term, Terms } from './expression';
export { Cluster, Index, Doc, Field, IntegerType, BooleanType, DateType, SearchQuery, Bool, RangeExpr, Term, Terms, };
export declare const fun: () => void;

@@ -7,9 +7,7 @@ "use strict";

const document_1 = require("./document");
exports.BooleanType = document_1.BooleanType;
exports.DateType = document_1.DateType;
exports.Doc = document_1.Doc;
exports.Field = document_1.Field;
exports.IntegerType = document_1.IntegerType;
exports.BooleanType = document_1.BooleanType;
exports.DateType = document_1.DateType;
const query_1 = require("./query");
exports.SearchQuery = query_1.SearchQuery;
const expression_1 = require("./expression");

@@ -20,1 +18,4 @@ exports.Bool = expression_1.Bool;

exports.Terms = expression_1.Terms;
const query_1 = require("./query");
exports.SearchQuery = query_1.SearchQuery;
exports.fun = () => console.log('this is fun!');

@@ -1,9 +0,10 @@

import { Expression, Params } from "./expression";
import { Cluster, Index } from "./cluster";
import { IDocument, Doc } from './document';
import { AggExpression } from "./agg";
import { SearchResult } from "./result";
import { AggExpression } from './agg';
import { Cluster, Index } from './cluster';
import { Doc, DocClass, Field } from './document';
import { Expression, Params, Sort, Source, SourceField } from './expression';
import { SearchResult } from './result';
import { Dictionary, Nullable, PlainObject } from './types';
export declare type SearchQueryOptions = {
routing?: number;
docClass?: IDocument;
docClass?: DocClass;
docType?: string;

@@ -16,6 +17,5 @@ };

export declare type SearchParams = {
routing?: number;
doc_type?: string;
routing?: string;
type?: string;
};
declare type SourceField = boolean | Array<string> | null;
declare type MatchValue = string | number | boolean;

@@ -25,25 +25,15 @@ declare type TermValue = string | number | boolean;

declare type MatchFilter = {
match: {
[field: string]: MatchValue;
};
match: Dictionary<string, MatchValue>;
};
declare type MatchPhraseFilter = {
match: {
[field: string]: MatchValue;
};
match: Dictionary<string, MatchValue>;
};
declare type TermFilter = {
term: {
[field: string]: TermValue;
};
term: Dictionary<string, TermValue>;
};
declare type TermsFilter = {
terms: {
[field: string]: Array<TermValue>;
};
terms: Dictionary<string, TermValue[]>;
};
declare type ExistsFilter = {
exists: {
[field: string]: ExistsValue;
};
exists: Dictionary<string, ExistsValue>;
};

@@ -54,3 +44,3 @@ declare type BoolField = {

};
declare type FilterRootField = BoolField | Array<ExistsFilter>;
declare type FilterRootField = BoolField | ExistsFilter[];
export declare type BoolMustFilter = Array<MatchFilter | MatchPhraseFilter>;

@@ -63,8 +53,4 @@ declare type BoolMustNotFilter = Array<MatchFilter | MatchPhraseFilter>;

};
declare type AggregationsField = {
[agg: string]: any;
};
export declare type Aggregations = {
[agg: string]: AggExpression;
};
declare type AggregationsField = PlainObject;
export declare type Aggregations = Dictionary<string, AggExpression>;
declare type QueryRootField = {

@@ -74,2 +60,9 @@ bool?: BoolRootField;

};
declare type SortOrder = 'asc' | 'desc';
declare type SortMode = 'min' | 'max' | 'sum' | 'avg' | 'median';
declare type SortObject = Dictionary<string, SortOrder | {
order: SortOrder;
mode?: SortMode;
}>;
declare type SortRootField = SortObject[] | string | '_score';
export declare type Query = {

@@ -80,4 +73,5 @@ query?: QueryRootField;

aggregations?: AggregationsField;
sort?: SortRootField;
};
export declare type QueryOverride = object | null;
export declare type QueryOverride = any | null;
export declare type Limit = number | null;

@@ -87,16 +81,24 @@ export declare type InstanceMapper<T1, T2> = (ids: T1[]) => T2;

query: QueryOverride;
source: SourceField;
fields: any;
filters: any;
source: Source | null;
fields: Field[];
filters: Expression[];
sort: Sort[];
limit: Limit;
searchParams: Params;
aggregations: Params;
docClass?: IDocument | undefined;
docClasses: Readonly<DocClass[]>;
docType?: string | undefined;
instanceMapper?: InstanceMapper<any, any> | undefined;
_visitName: string;
constructor(query: QueryOverride, source: SourceField, fields: any, filters: any, limit: Limit, searchParams: Params, aggregations: Params, docClass?: IDocument | undefined, // TODO maybe we should pass entire SearchQuery ?
instanceMapper?: InstanceMapper<any, any> | undefined);
visitName: string;
docTypes: Readonly<string[]>;
constructor(query: QueryOverride, source: Source | null, fields: Field[], filters: Expression[], sort: Sort[], limit: Limit, searchParams: Params, aggregations: Params, docClasses: Readonly<DocClass[]>, docType?: string | undefined, instanceMapper?: InstanceMapper<any, any> | undefined);
private getUniqueDocTypes;
}
export declare class SearchQuery {
private cluster?;
/**
* TODO this field needed when SearchQuery created on its own and hence not bound to cluster or query
* * implement check _index_or_cluster
* * add method for bound, like withIndex, withCluster
*/
private index?;

@@ -106,2 +108,3 @@ private _limit;

private _filters;
private _sort;
private _aggregations;

@@ -114,18 +117,30 @@ private _source;

private _instanceMapper?;
constructor(searchQueryOptions: ClusterSearchQueryOptions);
constructor(searchQueryOptions?: ClusterSearchQueryOptions);
getQueryContext(): SearchQueryContext;
/**
* Controls which fields of the document's ``_source`` field to retrieve.
* @param include
*
* @param fields: list of fields which should be returned by elasticsearch. Can be one of the following types:
* - field expression, for example: ``PostDocument.title``
* - ``str`` means field name or glob pattern. For example:
* ``"title"``, ``"user.*"``
* - ``False`` disables retrieving source
* - ``True`` enables retrieving all source document
* - ``None`` cancels source filtering applied before
* @param include: list of fields to include
* @param exclude: list of fields to exclu
* See `source filtering for more information.
* <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html>`_
*/
source(fields: SourceField): SearchQuery;
source(fields: boolean | null | undefined | string | Field | Array<string | Field>, opts?: {
include?: Array<string | Field>;
exclude?: Array<string | Field>;
}): this;
/**
* TODO maybe we need clone Query instance on filter call?
*
* Multiple expressions may be specified, so they will be joined together using ``Bool.must`` expression.
* @param filters
*/
filter(...filters: Expression[]): SearchQuery;
limit(limit: number): SearchQuery;
query(query: QueryOverride): SearchQuery;
filter(...filters: Expression[] | Nullable[]): this;
limit(limit: number): this;
query(query: QueryOverride): this;
/**

@@ -140,12 +155,19 @@ * Adds `aggregations <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html>`_

*/
aggregations(aggs: Aggregations): SearchQuery;
withInstanceMapper<T1, T2>(instanceMapper: InstanceMapper<T1, T2>): SearchQuery;
aggregations(aggs: Nullable<Aggregations>): this;
aggs(aggs: Nullable<Aggregations>): this;
withInstanceMapper<T1, T2>(instanceMapper: InstanceMapper<T1, T2>): this;
withDoc<T extends DocClass>(docClass: T): this;
withDocType(docType: string): this;
toJSON(): Query;
get body(): Query;
get params(): SearchParams;
get prettyBody(): string;
getResult<T extends Doc = any>(): Promise<SearchResult<T>>;
clone(): this;
sort(...orders: Sort[] | Field[] | Nullable[]): this;
orderBy(...orders: Sort[] | Field[] | Nullable[]): this;
private compile;
private prepareSearchParams;
get body(): Query;
get params(): any;
get prettyBody(): string;
getResult<T extends Doc = any, TRaw = any>(): Promise<SearchResult<T>>;
private collectDocClasses;
}
export {};

@@ -11,9 +11,13 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
const compiler_1 = require("./compiler");
const expression_1 = require("./expression");
const compiler_1 = require("./compiler");
const util_1 = require("./util");
// TODO make all fields readonly
class SearchQueryContext {
constructor(query, source, fields, filters, limit, searchParams, aggregations, docClass, // TODO maybe we should pass entire SearchQuery ?
instanceMapper) {
constructor(query, source, fields, filters, sort, limit, searchParams, aggregations, docClasses, docType, instanceMapper) {
this.query = query;

@@ -23,31 +27,49 @@ this.source = source;

this.filters = filters;
this.sort = sort;
this.limit = limit;
this.searchParams = searchParams;
this.aggregations = aggregations;
this.docClass = docClass;
this.docClasses = docClasses;
this.docType = docType;
this.instanceMapper = instanceMapper;
this._visitName = 'searchQueryContext';
if (!docClass) {
// TODO collect_doc_classes
this.visitName = 'searchQueryContext';
this.docTypes = [];
const docTypes = [];
// TODO debug this to make it right, maybe look at tests
if (docType) {
if (util_1.isString(docType)) {
docTypes.push(...docType.split(',').map((type) => type.trim()));
}
else {
docTypes.push(docType);
}
}
this.docTypes = this.getUniqueDocTypes(docTypes, this.docClasses);
}
getUniqueDocTypes(docTypes, docClasses) {
const docClassesTypes = docClasses.map((cls) => cls.getDocCls());
const uniqueDocTypes = new Set(docTypes.concat(docClassesTypes));
return Array.from(uniqueDocTypes);
}
}
exports.SearchQueryContext = SearchQueryContext;
// UTIL
function getDocType(docType, docClass) {
if (docType)
if (docType) {
return docType;
if (docClass)
return docClass._docType;
}
if (docClass) {
return docClass.docType;
}
return null;
}
class SearchQuery {
constructor(searchQueryOptions) {
constructor(searchQueryOptions = {}) {
this._limit = null;
this._fields = null; // TODO not used right now
this._fields = [];
this._filters = [];
this._sort = [];
this._aggregations = new expression_1.Params();
this._source = null;
this._query = null;
this._searchParams = new expression_1.Params(); // TODO maybe add subtype like SearchParams
this._searchParams = new expression_1.Params();
const { index, cluster, routing, docClass, docType, } = searchQueryOptions;

@@ -63,22 +85,42 @@ this.cluster = cluster;

this._searchParams = new expression_1.Params({
routing: routing,
docType: getDocType(docType, docClass),
routing,
});
}
getQueryContext() {
return new SearchQueryContext(this._query, this._source, this._fields, this._filters, this._limit, this._searchParams, this._aggregations, this._docClass, this._instanceMapper);
const docClasses = this._docClass ? [this._docClass] : this.collectDocClasses();
return new SearchQueryContext(this._query, this._source, this._fields, this._filters, this._sort, this._limit, this._searchParams, this._aggregations, docClasses, this._docType, this._instanceMapper);
}
/**
* Controls which fields of the document's ``_source`` field to retrieve.
* @param include
*
* @param fields: list of fields which should be returned by elasticsearch. Can be one of the following types:
* - field expression, for example: ``PostDocument.title``
* - ``str`` means field name or glob pattern. For example:
* ``"title"``, ``"user.*"``
* - ``False`` disables retrieving source
* - ``True`` enables retrieving all source document
* - ``None`` cancels source filtering applied before
* @param include: list of fields to include
* @param exclude: list of fields to exclu
* See `source filtering for more information.
* <https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html>`_
*/
source(fields) {
// TODO add exclude and include
this._source = fields;
source(fields, opts) {
var _a, _b, _c, _d, _e, _f;
if (util_1.isNullOrUndef(fields) || util_1.mustClean(fields)) {
this._source = null;
}
else if (util_1.isBoolean(fields)) {
this._source = new expression_1.Source(fields, (_a = opts) === null || _a === void 0 ? void 0 : _a.include, (_b = opts) === null || _b === void 0 ? void 0 : _b.exclude);
}
else if (util_1.isArray(fields)) {
this._source = new expression_1.Source(fields, (_c = opts) === null || _c === void 0 ? void 0 : _c.include, (_d = opts) === null || _d === void 0 ? void 0 : _d.exclude);
}
else {
this._source = new expression_1.Source(fields, (_e = opts) === null || _e === void 0 ? void 0 : _e.include, (_f = opts) === null || _f === void 0 ? void 0 : _f.exclude);
}
return this;
}
// TODO later there can be multiple filter func declarations, one with variadic args
/**
* TODO maybe we need clone Query instance on filter call?
*
* Multiple expressions may be specified, so they will be joined together using ``Bool.must`` expression.

@@ -88,3 +130,8 @@ * @param filters

filter(...filters) {
this._filters.push(...filters);
if (util_1.mustClean(filters)) {
this._filters = [];
}
else {
this._filters.push(...filters);
}
return this;

@@ -96,2 +143,3 @@ }

}
// TODO QueryOverride type is incorrect, hack
query(query) {

@@ -112,5 +160,14 @@ this._query = query;

// TODO implement null cleaning
this._aggregations = new expression_1.Params(aggs);
if (util_1.mustClean(aggs)) {
this._aggregations = new expression_1.Params();
}
else {
this._aggregations = util_1.mergeParams(this._aggregations, new expression_1.Params(aggs));
}
return this;
}
aggs(aggs) {
this.aggregations(aggs);
return this;
}
withInstanceMapper(instanceMapper) {

@@ -120,17 +177,13 @@ this._instanceMapper = instanceMapper;

}
withDoc(docClass) {
this._docClass = docClass;
return this;
}
withDocType(docType) {
this._docType = docType;
return this;
}
toJSON() {
return this.compile();
}
compile() {
const compiler = new compiler_1.CompilerVisitor();
return compiler.compile(this.getQueryContext());
}
prepareSearchParams(params) {
return {
routing: `${params.routing}`,
type: params.docType,
};
}
// TODO maybe reuse logic with Compiled.
// Like hold class which can compile all on construction and then use that instance?
get body() {

@@ -154,3 +207,39 @@ return this.toJSON();

}
clone() {
return lodash_clonedeep_1.default(this);
}
sort(...orders) {
if (util_1.mustClean(orders)) {
this._sort = [];
}
else {
this._sort.push(...orders);
}
return this;
}
orderBy(...orders) {
this.sort(...orders);
return this;
}
compile() {
const compiler = new compiler_1.CompilerVisitor();
return compiler.compile(this.getQueryContext());
}
prepareSearchParams(params) {
return {
routing: `${params.routing}`,
type: params.docType,
};
}
collectDocClasses() {
const expressions = [
this._query,
this._source,
this._fields,
this._filters,
Object.values(this._aggregations.getParams()),
];
return util_1.uniqueArray(util_1.flatMap((expr) => util_1.collectDocClasses(expr), expressions));
}
}
exports.SearchQuery = SearchQuery;

@@ -1,15 +0,16 @@

import { InstanceMapper } from "./query";
import { IDocument, Doc } from "./document";
import { Params } from "./expression";
import { Dictionary, RawResultBody } from "./types";
import { AggResult } from "./agg";
declare type InstanceMapperDict = Dictionary<string, InstanceMapper<IDocument, any>>;
import { AggResult } from './agg';
import { Doc, DocClass } from './document';
import { Params } from './expression';
import { InstanceMapper } from './query';
import { Dictionary, RawResultBody } from './types';
declare type InstanceMapperDict = Dictionary<string, InstanceMapper<DocClass, any>>;
declare class Result {
raw: any;
constructor(raw: any);
raw: RawResultBody<any>;
constructor(raw: RawResultBody<any>);
get prettyRaw(): string;
}
export declare class SearchResult<T extends Doc, TRaw = any> extends Result {
export declare class SearchResult<T extends Doc> extends Result {
private docClasses;
private queryAggs;
private docClsMap;
private docClasses;
private instanceMappers;

@@ -25,5 +26,6 @@ private mapperRegistry;

scrollId: number | undefined;
constructor(rawResult: RawResultBody<TRaw>, aggregations: Params, docClass?: IDocument, instanceMapper?: InstanceMapper<IDocument, any> | InstanceMapperDict);
constructor(rawResult: RawResultBody<any>, aggregations: Params, docClasses: Readonly<DocClass[]>, instanceMapper?: InstanceMapper<DocClass, any> | InstanceMapperDict);
getAggregation(name: string): AggResult;
getIds(): number[];
}
export {};

@@ -7,14 +7,4 @@ "use strict";

const DOC_TYPE_NAME_FIELD = `${DOC_TYPE_FIELD}.name`;
function docClsMap(docCls) {
let docClasses = [];
if (!docCls) {
docClasses = [];
}
else if (!Array.isArray(docCls)) {
docClasses = [docCls];
}
else {
docClasses = docCls;
}
return util_1.arrayKVToDict(docClasses.map((cls) => [cls._docType, cls]));
function docClsMap(docClasses) {
return util_1.arrayKVToDict(docClasses.map((cls) => [cls.docType, cls]));
}

@@ -33,10 +23,12 @@ function getDocTypeForHit(hit) {

}
;
get prettyRaw() {
return JSON.stringify(this.raw, null, 2);
}
}
class SearchResult extends Result {
constructor(rawResult, aggregations, docClass, instanceMapper) {
constructor(rawResult, aggregations, docClasses, instanceMapper) {
super(rawResult);
this.docClasses = docClasses;
this.queryAggs = new expression_1.Params();
this.docClsMap = {};
this.docClasses = [];
this.instanceMappers = {};

@@ -47,5 +39,6 @@ this.mapperRegistry = {};

this.queryAggs = aggregations || new expression_1.Params();
this.docClsMap = docClsMap(docClass);
this.docClasses = Object.values(this.docClsMap);
this.docClsMap = docClsMap(docClasses);
if (instanceMapper) {
// TODO although we can check if instanceMapper is a dict
// it is not implemented to accept instanceMapper at a higher level yet
if (isInstanceMapperDict(instanceMapper)) {

@@ -55,3 +48,3 @@ this.instanceMappers = instanceMapper;

else {
this.instanceMappers = util_1.arrayKVToDict(this.docClasses.map((cls) => [cls._docType, instanceMapper]));
this.instanceMappers = util_1.arrayKVToDict(this.docClasses.map((cls) => [cls.docType, instanceMapper]));
}

@@ -65,6 +58,6 @@ }

this.maxScore = hits.max_score;
// TODO add type for hit: any
hits.hits.forEach((hit) => {
const docType = getDocTypeForHit(hit);
const docCls = this.docClsMap[docType]; // TODO DynamicDocument
// TODO below use some sort of DynamicDocument, because fail if no docClass passed to SearchResult
const docCls = this.docClsMap[docType];
// TODO below is a hack

@@ -87,3 +80,6 @@ // the propblem is when having class type to create instance from it we need to know its type

}
getIds() {
return this.hits.map((hit) => Number(hit._id));
}
}
exports.SearchResult = SearchResult;

@@ -0,1 +1,2 @@

export declare type Nullable<T = any> = T | null | undefined;
export declare type Dictionary<T1 extends string | number, T2 = any> = {

@@ -15,28 +16,19 @@ [key in T1]: T2;

_type?: string;
_source: T;
_source?: T;
fields?: PlainObject;
};
declare type AggOpts = {
doc_count_error_upper_bound: number;
sum_other_doc_count: number;
declare type BucketFields = {
doc_count: number;
};
export declare type BucketAgg = {
[key: string]: Agg;
};
declare type AggBucketChild = {
[key: string]: {
doc_count: number;
} & AggBucketChild;
};
export declare type AggBucket = {
export declare type RawAggBucketChild = Dictionary<string, BucketFields | Dictionary<string, BucketFields>>;
export declare type RawAggBucket = {
key: any;
doc_count: number;
} & AggBucketChild;
export declare type Agg = {
} & RawAggBucketChild;
export declare type RawAgg = {
doc_count_error_upper_bound: number;
sum_other_doc_count: number;
buckets: Array<AggBucket>;
} & AggOpts;
declare type Aggs = {
[key: string]: Agg;
buckets: RawAggBucket[];
};
declare type RawAggs = Dictionary<string, RawAgg>;
declare type SearchResponseBody<T> = {

@@ -58,8 +50,5 @@ error?: string;

};
aggregations?: Aggs;
aggregations?: RawAggs;
};
declare type Source = {
[key: string]: any;
};
export declare type RawResultBody<T = Source> = SearchResponseBody<T>;
export declare type RawResultBody<T = PlainObject> = SearchResponseBody<T>;
export {};

@@ -1,2 +0,4 @@

import { ParamsType } from "./expression";
import { DocClass } from './document';
import { Expression, FieldQueryValue, Params, ParamsType } from './expression';
import { Nullable } from './types';
export declare function arrayKVToDict<T = any>(array: any[][]): T;

@@ -7,3 +9,13 @@ /**

*/
export declare function cleanParams(params?: ParamsType): ParamsType;
export declare function isObject(value: any): boolean;
export declare function cleanParams(params?: Nullable<ParamsType>): ParamsType;
export declare function isArray<T>(x: any): x is T[];
export declare function isString(x: any): x is string;
export declare function isBoolean(x: any): x is boolean;
export declare function isObject(x: any): x is object;
export declare function isExpression(x: any): x is Expression;
export declare function isNullOrUndef(x: any): x is null | undefined;
export declare function uniqueArray<T = any>(items: T[]): T[];
export declare function collectDocClasses(expr?: Expression | Expression[] | ParamsType | FieldQueryValue): Readonly<DocClass[]>;
export declare function mergeParams(currentParams: Params, newParams: Params): Params;
export declare function flatMap(f: (arg: any) => any, arr: any[]): any[];
export declare function mustClean(arg: any[] | Nullable): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const expression_1 = require("./expression");
function arrayKVToDict(array) {

@@ -15,4 +16,5 @@ return array.reduce((acc, [key, val]) => {

function cleanParams(params) {
if (!params)
if (!params) {
return {};
}
return Object.entries(params)

@@ -27,24 +29,67 @@ .reduce((acc, [key, val]) => {

exports.cleanParams = cleanParams;
// TODO maybe rewrite all to Map. Could it be slow ??
function isObject(value) {
const isObjectLike = typeof value === 'object' && value !== null;
let tag = null;
if (value == null) {
tag = value === undefined ? '[object Undefined]' : '[object Null]';
function isArray(x) {
return Array.isArray(x) && typeof x.length === 'number';
}
exports.isArray = isArray;
function isString(x) {
return typeof x === 'string';
}
exports.isString = isString;
function isBoolean(x) {
return typeof x === 'boolean';
}
exports.isBoolean = isBoolean;
function isObject(x) {
return x && typeof x === 'object' && x.constructor === Object;
}
exports.isObject = isObject;
function isExpression(x) {
return x instanceof expression_1.Expression;
}
exports.isExpression = isExpression;
function isNullOrUndef(x) {
return x === null || x === undefined;
}
exports.isNullOrUndef = isNullOrUndef;
function uniqueArray(items) {
return Array.from(new Set(items));
}
exports.uniqueArray = uniqueArray;
function collectDocClasses(expr) {
if (isExpression(expr)) {
return expr.collectDocClasses();
}
else {
tag = toString.call(value);
if (isArray(expr)) {
return uniqueArray(flatMap((item) => collectDocClasses(item), expr));
}
if (!isObjectLike || tag != '[object Object]') {
if (isObject(expr)) {
const kvListChain = Object.keys(expr).concat(Object.values(expr));
return uniqueArray(flatMap((item) => collectDocClasses(item), kvListChain));
}
return [];
}
exports.collectDocClasses = collectDocClasses;
function mergeParams(currentParams, newParams) {
return new expression_1.Params(Object.assign(Object.assign({}, currentParams.getParams()), newParams.getParams()));
}
exports.mergeParams = mergeParams;
function flatMap(f, arr) {
return arr.reduce((x, y) => [...x, ...f(y)], []);
}
exports.flatMap = flatMap;
function mustClean(arg) {
if (isBoolean(arg)) {
return false;
}
if (Object.getPrototypeOf(value) === null) {
if (isObject(arg) && Object.keys(arg).length === 0) {
return true;
}
let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
if (isArray(arg) && arg.length === 1) {
return isNullOrUndef(arg[0]);
}
return Object.getPrototypeOf(value) === proto;
if (isArray(arg) && arg.length === 0) {
return true;
}
return isNullOrUndef(arg) ? true : false;
}
exports.isObject = isObject;
exports.mustClean = mustClean;
{
"name": "elasticmagic",
"version": "0.0.4",
"version": "0.0.5",
"description": "JS orm for elasticsearch.",

@@ -16,4 +16,6 @@ "repository": {

"build": "tsc",
"test": "ES_HOST=es6 jest",
"test:integ": "ES_HOST=es6 jest tests/integ",
"test": "run-p test:unit test:integ",
"test:integ": "ES_HOST=es6 jest tests/integ --runInBand",
"test:unit": "ES_HOST=es6 jest tests/unit",
"test:one": "ES_HOST=es6 jest",
"test:ci": "ES_HOST=localhost jest",

@@ -32,5 +34,6 @@ "lint": "tslint -c tslint.json 'src/**/*.ts'",

"jest": "24.9.0",
"npm-run-all": "^4.1.5",
"ts-jest": "24.2.0",
"typescript": "3.7.4",
"tslint": "5.20.1"
"tslint": "5.20.1",
"typescript": "3.7.4"
},

@@ -37,0 +40,0 @@ "author": "Kindritskiy Maksym <kindritskiy.m@gmail.com>",

@@ -1,29 +0,44 @@

elasticmagic-js (alpha)
elasticmagic-js - JS/Typescript DSL for Elasticsearch
=======================
> This is alpha. Api may/will change.
> The project is still very much a work in progress and in an alpha state, api may/will change; input and contributions welcome!
JS/Typescript DSL for Elasticsearch
[![actions](https://github.com/kindritskyiMax/elasticmagic-js/workflows/tests/badge.svg?branch=master)](https://github.com/kindritskyiMax/elasticmagic-js/actions)
This lib is a port of original library written in `python` by [@anti-social]( https://github.com/anti-social/elasticmagic )
Elasticmagic is an Elasticsearch query builder and ORM for JavaScript/Typescript.
It helps you easily build queries which are typed and safe.
You do not need to remember how to write `json` DSL for Elasticsearch, Elasticmagic will do it for you.
> This lib is a port of original library written in `python` by [@anti-social]( https://github.com/anti-social/elasticmagic )
## Versions
Supports Elasticsearch version 6.x
# Getting Started
## Docs
Install elasticmagic-js using [`npm`](https://www.npmjs.com/):
**Docs** - [https://elasticmagic.js.org/](https://elasticmagic.js.org/)
**Changelog** - [https://elasticmagic.js.org/docs/changelog.html](elasticmagic.js.org/docs/changelog.html)
## Installation
To install Elasticmagic via NPM:
```bash
npm install elasticmagic
npm install --save elasticmagic
```
# Examples
Also you need an Elasticseach official js client
Let's get started by writing a simple query.
```bash
npm install --save @elastic/elasticsearch
```
1. Declare class. We will use it both as `query builder` and container for data from elastic.
## Getting Started
As you can see we declare one static field and one intance field with almost same name but different types.
Static field will be used to build queries.
Instance field will be populated on search query so they must be the same as in elasticsearch document.
#### Query building

@@ -40,27 +55,33 @@ ```javascript

enum OrderStatus {
new = 1,
paid = 2,
handled = 3,
canceled = 4,
}
enum OrderSource {
desktop = 1,
mobile = 2,
}
/**
* Here we creating our document which maps structure of same document in Elasticsearch.
*
* We will use this class as our query builder.
* Also when we will get result from elasticsearch, we instantiate this class
* and populate it with data from Elasticsearch hits.
*
* First we declare docType - it must be the same as document in Elasticsearch mapping.
*
* Then we declare static fields that will be user to build our queries.
* As we do not need an instance of this class to build queries, the fields are static.
*
* Next, conventionaly, we declare instance properties, as you can see, with almost same name.
* Then lettercase is same as fields in Elasticseach mapping
*
* And thats is.
*/
class OrderDoc extends Doc {
public static docType: string = 'order';
public static userId = new Field(DateType, 'user_id', OrderDoc);
public static userId = new Field(IntegerType, 'user_id', OrderDoc);
public user_id?: number;
public static status = new Field(DateType, 'status', OrderDoc);
public static status = new Field(IntegerType, 'status', OrderDoc);
public status?: number;
public static source = new Field(DateType, 'source', OrderDoc);
public static source = new Field(IntegerType, 'source', OrderDoc);
public source?: number;
public static price = new Field(DateType, 'price', OrderDoc);
public static price = new Field(IntegerType, 'price', OrderDoc);
public price?: number;

@@ -71,63 +92,40 @@

}
```
2. Create elasticsearch client and pass it to Cluester
```javascript
// Create a Elasticsearch client which will be passed to cluster.
const client = new Client({ node: 'http://es6-test:9200' });
// Create cluster instance. Its an entrypiint for interacting with Elasticsearch.
const cluster = new Cluster(client, 'test_order_index');
```
3. Now we ready to write our query
```javascript
// Lets start building our query.
// Calling searchQuery method we start creating new query.
// We using builder pattern, so you can chain any amount of methods
const query = cluster.searchQuery({ routing: 1 })
.source(false)
.source(true)
.filter(
Bool.must(
OrderDoc.user_id.in([1]),
OrderDoc.status.in([OrderStatus.new, OrderStatus.paid]),
OrderDoc.source.not(OrderSource.mobile),
OrderDoc.status.in([1, 2]),
OrderDoc.source.not(1),
OrderDoc.dateCreated.lte(new Date().toISOString())
)
)
.limit(0);
);
console.log(query.toJSON()) // or console.log(query.body)
```
// To make a query to Elasticsearch we calling getResult.
const result = await query.getResult<OrderDoc>();
console.log(result.getIds()); // prints ["1"]
It will print:
```bash
{
query: {
bool: {
filter: {
bool: {
must: [
{terms: {user_id: [1]}},
{terms: {status: [1, 2]}},
{bool: {
must_not: [
{term: {source: 2}}
]
}}
]
}
}
}
},
_source: false,
size: 0
}
const hit = result.hits[0];
console.log(hit.user_id); // prints 1
```
4. To fetch results from elasticsearch: Lets suppouse we have one doc in index with id 1.
We can check what query Elasticmagic will build for us.
```javascript
const result = await query.getResult<OrderDoc>();
console.log(result.getIds()); // prints [1]
const hit = result.hits[0];
console.log(query.toJSON())
// or alias
console.log(query.body)
console.log(hit.user_id); // prints 1
// to see prettified query
console.log(query.prettyQuery)
```

@@ -199,7 +197,4 @@

# Development
## Tests
#### Tests
Run all tests

@@ -219,23 +214,99 @@

# TODO
## TODO
- [ ] documentation (https://typedoc.org, docusaurus, js.org)
- [ ] add support for elasticsearch 5, 7 versions, compilers for different es versions
#### Document API (CRUD)
- [ ] Index API
- [ ] Get API
- [ ] Delete API
- [ ] Delete By Query API
- [ ] Update API
- [ ] Update By Query API
- [ ] Multi Get API
- [ ] Bulk API
- [ ] Reindex API
#### Query DSL
- [x] searchQuery
- [x] aggregations
- [ ] Match All Query
- [ ] Match All Query
- Full text queries
- [ ] Match Query
- [ ] Match Phrase Query
- [ ] Match Phrase PrefixQuery
- [ ] Multi Match Query
- [ ] Common Terms Query
- [ ] Query String Query
- [ ] Simple Query String Query
- Term level queries
- [x] Term Query
- [x] Terms Query
- [ ] Terms Set Query
- [x] Range Query
- [ ] Exists Query
- [ ] Prefix Query
- [ ] Wildcard Query
- [ ] Regexp Query
- [ ] Fuzzy Query
- [ ] Type Query
- [ ] Ids Query
- Compound queries
- [ ] Constant Score Query
- [ ] Bool Query
- [ ] Dis Max Query
- [ ] Function Score Query
- [ ] Boosting Query
- Joining queries
- [ ] Nested Query
- [ ] Has Child Query
- [ ] Has Parent Query
- [ ] Parent Id Query
- Specialized queries
- [ ] Distance Feature Query
- [ ] More Like This Query
- [ ] Script Query
- [ ] Script Score Query
- [ ] Percolate Query
- Sorting
- [ ] Sort by score
- [x] Sort by field
- [ ] Sort by geo distance
- [ ] Sort by script
- [ ] Sort by doc
#### Search APIs (
- [ ] Multi Search
- [ ] Search Shards API
- [ ] Multi Search API
- [ ] Count API
- [ ] Validate API
- [ ] Explain API
- [ ] Profile API
#### Elasticsearch versions interop
- [ ] add support for elasticsearch 5, 7 versions, compilers for different es versions
#### Development
- [ ] precommit hooks
- [ ] generate doc with jsDoc
- [ ] generate doc like ttag has
- [ ] elasticsearch must be devDep or peerDep, but not production dep (create Client interface)
- [ ] scroll
- [ ] pagination
- [ ] queryFilters
- [ ] function_score, inline functions
- [ ] sub documents
- [ ] more tests
- [ ] indexing, delete, bulk (CRUD)
- [ ] post_filters
- [ ] rescores
- [ ] highlight
- [ ] add doc to methods
- [ ] MultiMatch, Ids
- [ ] api docs
- [ ] fix integration tests by randomly creating indexes, so tests can be run in parallel
- [ ] add documentation to methods
- [ ] generate api docs (typedoc)
#### cat APIs
#### Other
- [ ] Post filters
- [ ] Rescores
- [ ] Scroll
- [ ] Pagination
- [ ] QueryFilters
- [ ] Sub document in field
- [ ] Sub field in field
- [ ] Highlight
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc