@opra/elastic 1.0.0-alpha.32 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/adapter-utils/prepare-filter.js +88 -80
- package/cjs/adapter-utils/prepare-patch.js +35 -0
- package/cjs/adapter-utils/prepare-projection.js +65 -108
- package/cjs/adapter-utils/prepare-sort.js +5 -6
- package/cjs/elastic-adapter.js +4 -7
- package/cjs/elastic-collection-service.js +365 -0
- package/cjs/elastic-entity-service.js +392 -0
- package/cjs/elastic-service.js +20 -103
- package/cjs/index.js +3 -0
- package/esm/adapter-utils/prepare-filter.js +88 -80
- package/esm/adapter-utils/prepare-patch.js +32 -0
- package/esm/adapter-utils/prepare-projection.js +62 -109
- package/esm/adapter-utils/prepare-sort.js +5 -6
- package/esm/elastic-adapter.js +4 -7
- package/esm/elastic-collection-service.js +361 -0
- package/esm/elastic-entity-service.js +388 -0
- package/esm/elastic-service.js +20 -103
- package/esm/index.js +3 -0
- package/esm/package.json +3 -0
- package/package.json +27 -35
- package/types/adapter-utils/prepare-filter.d.ts +3 -2
- package/types/adapter-utils/prepare-patch.d.ts +2 -0
- package/types/adapter-utils/prepare-projection.d.ts +7 -0
- package/types/elastic-adapter.d.ts +7 -2
- package/types/elastic-collection-service.d.ts +217 -0
- package/types/elastic-entity-service.d.ts +262 -0
- package/types/elastic-service.d.ts +20 -99
- package/types/index.d.cts +4 -0
- package/types/index.d.ts +3 -0
- package/cjs/adapter-utils/prepare-key-values.js +0 -22
- package/esm/adapter-utils/prepare-key-values.js +0 -18
- package/types/adapter-utils/prepare-key-values.d.ts +0 -1
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
/* eslint-disable camelcase */
|
|
2
2
|
import '@opra/core';
|
|
3
3
|
import { OpraFilter } from '@opra/common';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (!
|
|
4
|
+
export default function prepareFilter(filters) {
|
|
5
|
+
const filtersArray = Array.isArray(filters) ? filters : [filters];
|
|
6
|
+
if (!filtersArray.length)
|
|
7
7
|
return;
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const filter of filtersArray) {
|
|
10
|
+
if (!filter)
|
|
11
|
+
continue;
|
|
12
|
+
let x = filter;
|
|
13
|
+
if (typeof filter === 'string')
|
|
14
|
+
x = prepareFilterAst(OpraFilter.parse(filter));
|
|
15
|
+
else if (filter instanceof OpraFilter.Expression)
|
|
16
|
+
x = prepareFilterAst(filter);
|
|
17
|
+
out.push(x);
|
|
10
18
|
}
|
|
11
|
-
if (
|
|
19
|
+
if (out.length > 1) {
|
|
20
|
+
return { bool: { must: [...out] } };
|
|
21
|
+
}
|
|
22
|
+
return out[0] ? out[0] : undefined;
|
|
23
|
+
}
|
|
24
|
+
function prepareFilterAst(ast, negative) {
|
|
25
|
+
if (!ast)
|
|
26
|
+
return;
|
|
27
|
+
if (ast instanceof OpraFilter.QualifiedIdentifier ||
|
|
28
|
+
ast instanceof OpraFilter.NumberLiteral ||
|
|
12
29
|
ast instanceof OpraFilter.StringLiteral ||
|
|
13
30
|
ast instanceof OpraFilter.BooleanLiteral ||
|
|
14
31
|
ast instanceof OpraFilter.NullLiteral ||
|
|
@@ -17,86 +34,77 @@ export default function prepareFilter(ast, negative) {
|
|
|
17
34
|
return ast.value;
|
|
18
35
|
}
|
|
19
36
|
if (ast instanceof OpraFilter.ArrayExpression) {
|
|
20
|
-
return ast.items.map(x =>
|
|
37
|
+
return ast.items.map(x => prepareFilterAst(x, negative));
|
|
21
38
|
}
|
|
22
39
|
if (ast instanceof OpraFilter.NegativeExpression) {
|
|
23
|
-
return
|
|
40
|
+
return prepareFilterAst(ast.expression, !negative);
|
|
24
41
|
}
|
|
25
42
|
if (ast instanceof OpraFilter.LogicalExpression) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
return wrapNot({
|
|
35
|
-
bool: { should: v },
|
|
36
|
-
}, negative);
|
|
43
|
+
const items = ast.items
|
|
44
|
+
.map(x => prepareFilterAst(x))
|
|
45
|
+
/** Filter nullish items */
|
|
46
|
+
.filter(x => x != null);
|
|
47
|
+
const k = (ast.op === 'or' ? 'should' : 'must') + (negative ? '_not' : '');
|
|
48
|
+
return { bool: { [k]: items } };
|
|
37
49
|
}
|
|
38
50
|
if (ast instanceof OpraFilter.ParenthesizedExpression) {
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
if (ast instanceof OpraFilter.ComparisonExpression)
|
|
42
|
-
return _transformComparisonExpression(ast, !!negative);
|
|
43
|
-
throw new Error(`${ast.kind} is not implemented yet`);
|
|
44
|
-
}
|
|
45
|
-
function _transformComparisonExpression(ast, negative) {
|
|
46
|
-
const left = prepareFilter(ast.left, negative);
|
|
47
|
-
if (ast.right instanceof OpraFilter.QualifiedIdentifier) {
|
|
48
|
-
throw new TypeError('not implemented yet');
|
|
51
|
+
return prepareFilterAst(ast.expression, negative);
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
53
|
+
if (ast instanceof OpraFilter.ComparisonExpression) {
|
|
54
|
+
if (!(ast.left instanceof OpraFilter.QualifiedIdentifier)) {
|
|
55
|
+
throw new Error('Left side of ComparisonExpression must be a QualifiedIdentifier');
|
|
56
|
+
}
|
|
57
|
+
const left = prepareFilterAst(ast.left);
|
|
58
|
+
const right = prepareFilterAst(ast.right);
|
|
59
|
+
let out;
|
|
60
|
+
if (right == null) {
|
|
61
|
+
negative = !negative;
|
|
62
|
+
out = { exists: { field: left } };
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
switch (ast.op) {
|
|
66
|
+
case '!=':
|
|
67
|
+
case '=':
|
|
68
|
+
case 'in':
|
|
69
|
+
case '!in': {
|
|
70
|
+
out = { match: { [left]: right } };
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case '>': {
|
|
74
|
+
out = { range: { [left]: { gt: right } } };
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case '>=': {
|
|
78
|
+
out = { range: { [left]: { gte: right } } };
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case '<': {
|
|
82
|
+
out = { range: { [left]: { lt: right } } };
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case '<=': {
|
|
86
|
+
out = { range: { [left]: { lte: right } } };
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case '!like':
|
|
90
|
+
case 'like': {
|
|
91
|
+
out = { wildcard: { [left]: { value: String(right).replace(/%/g, '*') } } };
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case '!ilike':
|
|
95
|
+
case 'ilike': {
|
|
96
|
+
out = { wildcard: { [left]: { value: String(right).replace(/%/g, '*'), case_insensitive: true } } };
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
default:
|
|
100
|
+
/* istanbul ignore next */
|
|
101
|
+
throw new TypeError(`Unknown ComparisonExpression operation (${ast.op})`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if ((ast.op.startsWith('!') && !negative) || (!ast.op.startsWith('!') && negative)) {
|
|
105
|
+
return { bool: { must_not: { ...out } } };
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
99
108
|
}
|
|
100
|
-
throw new Error(
|
|
109
|
+
throw new Error(`${ast.kind} is not implemented yet`);
|
|
101
110
|
}
|
|
102
|
-
const wrapNot = (o, negative) => (negative ? { bool: { must_not: o } } : o);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export default function preparePatch(doc) {
|
|
2
|
+
const script = [];
|
|
3
|
+
const params = {};
|
|
4
|
+
_preparePatch(doc, script, params, '');
|
|
5
|
+
return {
|
|
6
|
+
source: script.join('\n'),
|
|
7
|
+
params,
|
|
8
|
+
lang: 'painless',
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function _preparePatch(src, script, params, path) {
|
|
12
|
+
let f;
|
|
13
|
+
let field;
|
|
14
|
+
for (const [k, v] of Object.entries(src)) {
|
|
15
|
+
f = k.startsWith('*') ? k.substring(1) : k;
|
|
16
|
+
field = path ? path + '.' + f : f;
|
|
17
|
+
if (v == null) {
|
|
18
|
+
script.push(`ctx._source.remove('${field}');`);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (v &&
|
|
22
|
+
typeof v === 'object' &&
|
|
23
|
+
!Array.isArray(v) &&
|
|
24
|
+
/** If field name starts with "*", do "replace" operation except "merge" */
|
|
25
|
+
!k.startsWith('*')) {
|
|
26
|
+
_preparePatch(v, script, params, field);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
script.push(`ctx._source['${field}'] = params['${field}'];`);
|
|
30
|
+
params[field] = v;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1,109 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// // include?: string[];
|
|
64
|
-
// // },
|
|
65
|
-
// // ): any {
|
|
66
|
-
// // let includes: string[] | undefined;
|
|
67
|
-
// // let excludes: string[] | undefined;
|
|
68
|
-
// //
|
|
69
|
-
// // if (args.include && !args.pick) {
|
|
70
|
-
// // includes = includes || [];
|
|
71
|
-
// // for (const [k, f] of dataType.fields) {
|
|
72
|
-
// // if (f.exclusive) continue;
|
|
73
|
-
// // if (f.type instanceof ComplexType) includes.push(k + '.*');
|
|
74
|
-
// // else includes.push(k);
|
|
75
|
-
// // }
|
|
76
|
-
// // }
|
|
77
|
-
// //
|
|
78
|
-
// // if (args.pick) {
|
|
79
|
-
// // includes = includes || [];
|
|
80
|
-
// // for (const k of args.pick) {
|
|
81
|
-
// // const f = dataType.getField(k);
|
|
82
|
-
// // if (f.type instanceof ComplexType) includes.push(k + '.*');
|
|
83
|
-
// // else includes.push(k);
|
|
84
|
-
// // }
|
|
85
|
-
// // }
|
|
86
|
-
// //
|
|
87
|
-
// // if (args.include) {
|
|
88
|
-
// // includes = includes || [];
|
|
89
|
-
// // for (const k of args.include) {
|
|
90
|
-
// // const f = dataType.getField(k);
|
|
91
|
-
// // if (f.type instanceof ComplexType) includes.push(k + '.*');
|
|
92
|
-
// // else includes.push(k);
|
|
93
|
-
// // }
|
|
94
|
-
// // }
|
|
95
|
-
// //
|
|
96
|
-
// // if (args.omit) {
|
|
97
|
-
// // excludes = excludes || [];
|
|
98
|
-
// // for (const k of args.omit) {
|
|
99
|
-
// // const f = dataType.getField(k);
|
|
100
|
-
// // if (f.type instanceof ComplexType) excludes.push(k + '.*');
|
|
101
|
-
// // else excludes.push(k);
|
|
102
|
-
// // }
|
|
103
|
-
// // }
|
|
104
|
-
// //
|
|
105
|
-
// // return omitNullish({
|
|
106
|
-
// // includes,
|
|
107
|
-
// // excludes,
|
|
108
|
-
// // });
|
|
109
|
-
// // }
|
|
1
|
+
import { ComplexType, parseFieldsProjection } from '@opra/common';
|
|
2
|
+
export default function prepareProjection(dataType, projection) {
|
|
3
|
+
const out = {};
|
|
4
|
+
const includes = [];
|
|
5
|
+
const excludes = [];
|
|
6
|
+
const projection_ = typeof projection === 'string' || Array.isArray(projection) ? parseFieldsProjection(projection) : projection;
|
|
7
|
+
prepare(dataType, includes, excludes, '', projection_);
|
|
8
|
+
if (includes.length)
|
|
9
|
+
out.includes = includes;
|
|
10
|
+
if (excludes.length)
|
|
11
|
+
out.excludes = excludes;
|
|
12
|
+
return includes.length || excludes.length ? out : undefined;
|
|
13
|
+
}
|
|
14
|
+
function getNeedIncludes(projection) {
|
|
15
|
+
return !!(projection && Object.values(projection).find(p => !p.sign));
|
|
16
|
+
}
|
|
17
|
+
export function prepare(dataType, includes, excludes, curPath, projection) {
|
|
18
|
+
const needIncludes = getNeedIncludes(projection);
|
|
19
|
+
const projectionKeys = projection && Object.keys(projection);
|
|
20
|
+
const projectionKeysSet = new Set(projectionKeys);
|
|
21
|
+
let fieldName;
|
|
22
|
+
let fieldPath;
|
|
23
|
+
let field;
|
|
24
|
+
let k;
|
|
25
|
+
/** Add fields from data type */
|
|
26
|
+
for (field of dataType.fields.values()) {
|
|
27
|
+
fieldName = field.name;
|
|
28
|
+
fieldPath = curPath + (curPath ? '.' : '') + fieldName;
|
|
29
|
+
k = fieldName.toLowerCase();
|
|
30
|
+
projectionKeysSet.delete(k);
|
|
31
|
+
const p = projection?.[k];
|
|
32
|
+
if (
|
|
33
|
+
/** if field is omitted */
|
|
34
|
+
p?.sign === '-' ||
|
|
35
|
+
/** if no projection defined for this field and includeDefaultFields is true and the field is exclusive */
|
|
36
|
+
(!p && field.exclusive)) {
|
|
37
|
+
if (!needIncludes)
|
|
38
|
+
excludes.push(fieldPath);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (needIncludes && p && !includes.includes(fieldPath)) {
|
|
42
|
+
if (!getNeedIncludes(p?.projection)) {
|
|
43
|
+
includes.push(fieldPath);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (field.type instanceof ComplexType && typeof p?.projection === 'object') {
|
|
47
|
+
prepare(field.type, includes, excludes, fieldPath, p.projection);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (dataType.additionalFields) {
|
|
51
|
+
for (k of projectionKeysSet.values()) {
|
|
52
|
+
const n = projection?.[k];
|
|
53
|
+
fieldPath = curPath + (curPath ? '.' : '') + k;
|
|
54
|
+
if (n?.sign === '-') {
|
|
55
|
+
if (!needIncludes)
|
|
56
|
+
excludes.push(fieldPath);
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
includes.push(fieldPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
+
const SIGN_PATTERN = /^([+-])?(.+)$/;
|
|
1
2
|
export default function prepareSort(sort) {
|
|
2
3
|
if (!(sort && sort.length))
|
|
3
4
|
return;
|
|
4
5
|
const out = [];
|
|
5
6
|
sort.forEach(k => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
else
|
|
11
|
-
out.push(k);
|
|
7
|
+
const m = SIGN_PATTERN.exec(k);
|
|
8
|
+
if (m) {
|
|
9
|
+
out.push({ [m[2]]: { order: m[1] === '-' ? 'desc' : 'asc' } });
|
|
10
|
+
}
|
|
12
11
|
});
|
|
13
12
|
return out;
|
|
14
13
|
}
|
package/esm/elastic-adapter.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
// import { SearchRequest } from '@elastic/elasticsearch/lib/api/types';
|
|
2
|
-
// import { TransportRequestOptions } from '@elastic/transport';
|
|
3
|
-
// import { omitNullish } from '@opra/common';
|
|
4
1
|
import _prepareFilter from './adapter-utils/prepare-filter.js';
|
|
5
|
-
import
|
|
6
|
-
|
|
2
|
+
import _preparePatch from './adapter-utils/prepare-patch.js';
|
|
3
|
+
import _prepareProjection from './adapter-utils/prepare-projection.js';
|
|
7
4
|
import _prepareSort from './adapter-utils/prepare-sort.js';
|
|
8
5
|
export var ElasticAdapter;
|
|
9
6
|
(function (ElasticAdapter) {
|
|
10
7
|
ElasticAdapter.prepareFilter = _prepareFilter;
|
|
11
|
-
ElasticAdapter.
|
|
12
|
-
|
|
8
|
+
ElasticAdapter.preparePatch = _preparePatch;
|
|
9
|
+
ElasticAdapter.prepareProjection = _prepareProjection;
|
|
13
10
|
ElasticAdapter.prepareSort = _prepareSort;
|
|
14
11
|
async function parseRequest(context) {
|
|
15
12
|
const { operation } = context;
|