kuzzle 2.19.2 → 2.19.3
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/lib/api/controllers/adminController.js +94 -80
- package/lib/api/controllers/authController.js +239 -212
- package/lib/api/controllers/baseController.js +89 -51
- package/lib/api/controllers/bulkController.js +62 -49
- package/lib/api/controllers/clusterController.js +6 -8
- package/lib/api/controllers/collectionController.js +140 -129
- package/lib/api/controllers/debugController.d.ts +2 -2
- package/lib/api/controllers/debugController.js +33 -31
- package/lib/api/controllers/documentController.js +365 -274
- package/lib/api/controllers/index.js +13 -13
- package/lib/api/controllers/indexController.js +46 -50
- package/lib/api/controllers/memoryStorageController.js +410 -360
- package/lib/api/controllers/realtimeController.js +37 -36
- package/lib/api/controllers/securityController.js +553 -412
- package/lib/api/controllers/serverController.js +111 -104
- package/lib/api/documentExtractor.js +75 -68
- package/lib/api/funnel.js +411 -312
- package/lib/api/httpRoutes.js +1493 -324
- package/lib/api/openapi/OpenApiManager.d.ts +1 -1
- package/lib/api/openapi/OpenApiManager.js +22 -22
- package/lib/api/openapi/components/document/count.yaml +1 -1
- package/lib/api/openapi/components/document/create.yaml +2 -2
- package/lib/api/openapi/components/document/delete.yaml +1 -1
- package/lib/api/openapi/components/document/deleteByQuery.yaml +1 -1
- package/lib/api/openapi/components/document/exists.yaml +1 -1
- package/lib/api/openapi/components/document/get.yaml +2 -2
- package/lib/api/openapi/components/document/index.js +12 -12
- package/lib/api/openapi/components/document/replace.yaml +1 -1
- package/lib/api/openapi/components/document/scroll.yaml +1 -1
- package/lib/api/openapi/components/document/validate.yaml +1 -1
- package/lib/api/openapi/components/index.d.ts +2 -2
- package/lib/api/openapi/components/index.js +1 -1
- package/lib/api/openapi/components/security/index.js +1 -1
- package/lib/api/openapi/components/security/upsertUser.yaml +2 -3
- package/lib/api/openapi/index.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.d.ts +1 -1
- package/lib/api/openapi/openApiGenerator.js +7 -7
- package/lib/api/rateLimiter.js +12 -13
- package/lib/api/request/index.d.ts +4 -4
- package/lib/api/request/kuzzleRequest.d.ts +9 -9
- package/lib/api/request/kuzzleRequest.js +89 -87
- package/lib/api/request/requestContext.d.ts +2 -2
- package/lib/api/request/requestContext.js +17 -17
- package/lib/api/request/requestInput.d.ts +1 -1
- package/lib/api/request/requestInput.js +19 -19
- package/lib/api/request/requestResponse.d.ts +4 -4
- package/lib/api/request/requestResponse.js +31 -33
- package/lib/cluster/command.js +48 -44
- package/lib/cluster/idCardHandler.d.ts +1 -1
- package/lib/cluster/idCardHandler.js +15 -15
- package/lib/cluster/index.js +2 -2
- package/lib/cluster/node.js +301 -269
- package/lib/cluster/publisher.js +45 -46
- package/lib/cluster/state.d.ts +5 -5
- package/lib/cluster/state.js +8 -8
- package/lib/cluster/subscriber.js +163 -113
- package/lib/cluster/workers/IDCardRenewer.js +33 -32
- package/lib/config/default.config.d.ts +1 -1
- package/lib/config/default.config.js +212 -171
- package/lib/config/documentEventAliases.js +6 -6
- package/lib/config/index.js +161 -98
- package/lib/config/sdkCompatibility.json +8 -8
- package/lib/core/auth/formatProcessing.js +7 -7
- package/lib/core/auth/passportResponse.js +7 -7
- package/lib/core/auth/passportWrapper.js +34 -30
- package/lib/core/auth/tokenManager.d.ts +2 -2
- package/lib/core/auth/tokenManager.js +11 -10
- package/lib/core/backend/applicationManager.d.ts +1 -1
- package/lib/core/backend/applicationManager.js +2 -2
- package/lib/core/backend/backend.d.ts +3 -3
- package/lib/core/backend/backend.js +34 -31
- package/lib/core/backend/backendCluster.d.ts +2 -2
- package/lib/core/backend/backendCluster.js +5 -5
- package/lib/core/backend/backendConfig.d.ts +2 -2
- package/lib/core/backend/backendConfig.js +3 -3
- package/lib/core/backend/backendController.d.ts +2 -2
- package/lib/core/backend/backendController.js +9 -10
- package/lib/core/backend/backendErrors.d.ts +3 -3
- package/lib/core/backend/backendErrors.js +2 -1
- package/lib/core/backend/backendHook.d.ts +2 -2
- package/lib/core/backend/backendHook.js +5 -5
- package/lib/core/backend/backendImport.d.ts +3 -3
- package/lib/core/backend/backendImport.js +23 -23
- package/lib/core/backend/backendOpenApi.d.ts +2 -2
- package/lib/core/backend/backendOpenApi.js +16 -16
- package/lib/core/backend/backendPipe.d.ts +2 -2
- package/lib/core/backend/backendPipe.js +6 -6
- package/lib/core/backend/backendPlugin.d.ts +4 -4
- package/lib/core/backend/backendPlugin.js +14 -14
- package/lib/core/backend/backendStorage.d.ts +2 -2
- package/lib/core/backend/backendStorage.js +1 -2
- package/lib/core/backend/backendVault.d.ts +2 -2
- package/lib/core/backend/backendVault.js +3 -3
- package/lib/core/backend/index.d.ts +14 -14
- package/lib/core/backend/internalLogger.d.ts +1 -1
- package/lib/core/backend/internalLogger.js +5 -5
- package/lib/core/cache/cacheDbEnum.js +4 -4
- package/lib/core/cache/cacheEngine.js +79 -85
- package/lib/core/network/accessLogger.js +126 -120
- package/lib/core/network/clientConnection.js +5 -5
- package/lib/core/network/context.js +8 -8
- package/lib/core/network/entryPoint.js +100 -85
- package/lib/core/network/httpRouter/index.js +63 -60
- package/lib/core/network/httpRouter/routeHandler.js +18 -19
- package/lib/core/network/httpRouter/routePart.js +23 -19
- package/lib/core/network/protocolManifest.js +3 -3
- package/lib/core/network/protocols/httpMessage.js +8 -10
- package/lib/core/network/protocols/httpwsProtocol.js +305 -250
- package/lib/core/network/protocols/internalProtocol.js +27 -24
- package/lib/core/network/protocols/mqttProtocol.js +106 -96
- package/lib/core/network/protocols/protocol.js +20 -17
- package/lib/core/network/router.js +56 -46
- package/lib/core/plugin/plugin.js +151 -120
- package/lib/core/plugin/pluginContext.d.ts +7 -7
- package/lib/core/plugin/pluginContext.js +48 -44
- package/lib/core/plugin/pluginManifest.js +13 -12
- package/lib/core/plugin/pluginRepository.js +26 -27
- package/lib/core/plugin/pluginsManager.js +425 -304
- package/lib/core/plugin/privilegedContext.js +3 -3
- package/lib/core/realtime/actionEnum.js +1 -1
- package/lib/core/realtime/channel.d.ts +1 -1
- package/lib/core/realtime/channel.js +22 -22
- package/lib/core/realtime/connectionRooms.d.ts +1 -1
- package/lib/core/realtime/hotelClerk.d.ts +2 -2
- package/lib/core/realtime/hotelClerk.js +53 -50
- package/lib/core/realtime/index.js +5 -5
- package/lib/core/realtime/notification/document.js +25 -25
- package/lib/core/realtime/notification/index.js +4 -4
- package/lib/core/realtime/notification/server.js +3 -3
- package/lib/core/realtime/notification/user.js +4 -4
- package/lib/core/realtime/notifier.js +113 -75
- package/lib/core/realtime/room.d.ts +1 -1
- package/lib/core/realtime/subscription.d.ts +1 -1
- package/lib/core/realtime/subscription.js +1 -1
- package/lib/core/security/index.js +8 -8
- package/lib/core/security/profileRepository.d.ts +6 -6
- package/lib/core/security/profileRepository.js +48 -45
- package/lib/core/security/roleRepository.js +127 -115
- package/lib/core/security/securityLoader.js +70 -63
- package/lib/core/security/tokenRepository.js +132 -118
- package/lib/core/security/userRepository.js +104 -88
- package/lib/core/shared/KoncordeWrapper.d.ts +1 -1
- package/lib/core/shared/KoncordeWrapper.js +3 -1
- package/lib/core/shared/abstractManifest.js +22 -23
- package/lib/core/shared/repository.js +69 -67
- package/lib/core/shared/sdk/embeddedSdk.d.ts +2 -2
- package/lib/core/shared/sdk/embeddedSdk.js +36 -32
- package/lib/core/shared/sdk/funnelProtocol.d.ts +1 -1
- package/lib/core/shared/sdk/funnelProtocol.js +11 -11
- package/lib/core/shared/sdk/impersonatedSdk.js +19 -18
- package/lib/core/shared/store.js +127 -32
- package/lib/core/statistics/index.js +2 -2
- package/lib/core/statistics/statistics.js +99 -85
- package/lib/core/storage/clientAdapter.js +219 -136
- package/lib/core/storage/indexCache.js +3 -3
- package/lib/core/storage/storageEngine.js +10 -13
- package/lib/core/storage/storeScopeEnum.js +3 -3
- package/lib/core/validation/baseType.js +12 -10
- package/lib/core/validation/index.js +2 -2
- package/lib/core/validation/types/anything.js +4 -4
- package/lib/core/validation/types/boolean.js +7 -7
- package/lib/core/validation/types/date.js +165 -131
- package/lib/core/validation/types/email.js +18 -21
- package/lib/core/validation/types/enum.js +34 -21
- package/lib/core/validation/types/geoPoint.js +7 -7
- package/lib/core/validation/types/geoShape.js +148 -125
- package/lib/core/validation/types/integer.js +9 -9
- package/lib/core/validation/types/ipAddress.js +17 -19
- package/lib/core/validation/types/numeric.js +36 -29
- package/lib/core/validation/types/object.js +19 -19
- package/lib/core/validation/types/string.js +36 -29
- package/lib/core/validation/types/url.js +17 -19
- package/lib/core/validation/validation.js +422 -378
- package/lib/kerror/codes/1-services.json +7 -1
- package/lib/kerror/codes/4-plugin.json +2 -2
- package/lib/kerror/codes/index.js +85 -63
- package/lib/kerror/errors/badRequestError.d.ts +1 -1
- package/lib/kerror/errors/externalServiceError.d.ts +1 -1
- package/lib/kerror/errors/forbiddenError.d.ts +1 -1
- package/lib/kerror/errors/gatewayTimeoutError.d.ts +1 -1
- package/lib/kerror/errors/index.d.ts +15 -15
- package/lib/kerror/errors/internalError.d.ts +1 -1
- package/lib/kerror/errors/kuzzleError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.d.ts +1 -1
- package/lib/kerror/errors/multipleErrorsError.js +1 -1
- package/lib/kerror/errors/notFoundError.d.ts +1 -1
- package/lib/kerror/errors/partialError.d.ts +1 -1
- package/lib/kerror/errors/partialError.js +1 -1
- package/lib/kerror/errors/pluginImplementationError.d.ts +1 -1
- package/lib/kerror/errors/pluginImplementationError.js +2 -1
- package/lib/kerror/errors/preconditionError.d.ts +1 -1
- package/lib/kerror/errors/serviceUnavailableError.d.ts +1 -1
- package/lib/kerror/errors/sizeLimitError.d.ts +1 -1
- package/lib/kerror/errors/tooManyRequestsError.d.ts +1 -1
- package/lib/kerror/errors/unauthorizedError.d.ts +1 -1
- package/lib/kerror/index.d.ts +3 -3
- package/lib/kerror/index.js +17 -16
- package/lib/kuzzle/dumpGenerator.js +130 -114
- package/lib/kuzzle/event/kuzzleEventEmitter.js +96 -70
- package/lib/kuzzle/event/pipeRunner.js +25 -24
- package/lib/kuzzle/event/waterfall.js +13 -15
- package/lib/kuzzle/index.js +2 -2
- package/lib/kuzzle/internalIndexHandler.js +80 -59
- package/lib/kuzzle/kuzzle.js +99 -99
- package/lib/kuzzle/kuzzleStateEnum.js +1 -1
- package/lib/kuzzle/log.js +23 -18
- package/lib/kuzzle/vault.js +34 -19
- package/lib/model/security/profile.d.ts +3 -3
- package/lib/model/security/profile.js +38 -37
- package/lib/model/security/rights.js +5 -5
- package/lib/model/security/role.d.ts +3 -3
- package/lib/model/security/role.js +25 -26
- package/lib/model/security/token.d.ts +1 -1
- package/lib/model/security/token.js +4 -4
- package/lib/model/security/user.d.ts +2 -2
- package/lib/model/security/user.js +9 -9
- package/lib/model/storage/apiKey.js +43 -33
- package/lib/model/storage/baseModel.js +49 -45
- package/lib/service/cache/redis.js +60 -55
- package/lib/service/service.js +17 -17
- package/lib/service/storage/elasticsearch.js +839 -755
- package/lib/service/storage/esWrapper.js +103 -86
- package/lib/service/storage/queryTranslator.js +52 -59
- package/lib/types/Controller.d.ts +3 -3
- package/lib/types/ControllerDefinition.d.ts +3 -3
- package/lib/types/DebugModule.d.ts +2 -2
- package/lib/types/DebugModule.js +1 -1
- package/lib/types/Global.d.ts +1 -1
- package/lib/types/HttpStream.d.ts +2 -1
- package/lib/types/HttpStream.js +7 -5
- package/lib/types/Kuzzle.d.ts +1 -1
- package/lib/types/KuzzleDocument.d.ts +1 -1
- package/lib/types/OpenApiDefinition.d.ts +1 -1
- package/lib/types/PasswordPolicy.d.ts +1 -1
- package/lib/types/Plugin.d.ts +6 -6
- package/lib/types/Plugin.js +2 -2
- package/lib/types/Policy.d.ts +1 -1
- package/lib/types/RequestPayload.d.ts +1 -1
- package/lib/types/ResponsePayload.d.ts +1 -1
- package/lib/types/Token.d.ts +1 -1
- package/lib/types/User.d.ts +1 -1
- package/lib/types/config/DumpConfiguration.d.ts +8 -8
- package/lib/types/config/HttpConfiguration.d.ts +1 -1
- package/lib/types/config/KuzzleConfiguration.d.ts +1 -1
- package/lib/types/config/LimitsConfiguration.d.ts +8 -8
- package/lib/types/config/PluginsConfiguration.d.ts +4 -4
- package/lib/types/config/SecurityConfiguration.d.ts +62 -62
- package/lib/types/config/ServerConfiguration.d.ts +55 -55
- package/lib/types/config/ServicesConfiguration.d.ts +2 -2
- package/lib/types/config/internalCache/InternalCacheRedisConfiguration.d.ts +10 -10
- package/lib/types/config/publicCache/PublicCacheRedisConfiguration.d.ts +3 -3
- package/lib/types/config/storageEngine/StorageEngineElasticsearchConfiguration.d.ts +194 -110
- package/lib/types/errors/ErrorDefinition.d.ts +1 -1
- package/lib/types/errors/ErrorDomains.d.ts +1 -1
- package/lib/types/index.d.ts +38 -38
- package/lib/types/realtime/RealtimeScope.d.ts +1 -1
- package/lib/types/realtime/RealtimeUsers.d.ts +1 -1
- package/lib/util/assertType.js +13 -11
- package/lib/util/async.d.ts +1 -0
- package/lib/util/async.js +61 -0
- package/lib/util/asyncStore.js +19 -21
- package/lib/util/bufferedPassThrough.d.ts +2 -2
- package/lib/util/bufferedPassThrough.js +4 -4
- package/lib/util/bytes.js +9 -13
- package/lib/util/crypto.js +1 -1
- package/lib/util/debug.js +5 -5
- package/lib/util/deprecate.js +24 -21
- package/lib/util/didYouMean.js +7 -7
- package/lib/util/dump-collection.d.ts +2 -2
- package/lib/util/dump-collection.js +26 -26
- package/lib/util/esRequest.d.ts +1 -0
- package/lib/util/esRequest.js +62 -0
- package/lib/util/extractFields.js +24 -25
- package/lib/util/inflector.js +5 -5
- package/lib/util/koncordeCompat.d.ts +2 -2
- package/lib/util/koncordeCompat.js +5 -5
- package/lib/util/memoize.js +3 -5
- package/lib/util/mutex.d.ts +19 -1
- package/lib/util/mutex.js +39 -12
- package/lib/util/name-generator.js +1331 -1331
- package/lib/util/promback.js +8 -10
- package/lib/util/readYamlFile.d.ts +1 -1
- package/lib/util/readYamlFile.js +1 -1
- package/lib/util/requestAssertions.js +34 -34
- package/lib/util/safeObject.js +5 -5
- package/lib/util/stackTrace.js +20 -22
- package/lib/util/wildcard.js +15 -15
- package/package.json +6 -6
- package/npm-shrinkwrap.json +0 -19422
|
@@ -19,49 +19,54 @@
|
|
|
19
19
|
* limitations under the License.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const assert = require(
|
|
25
|
-
const _ = require(
|
|
26
|
-
const { Client: StorageClient } = require(
|
|
27
|
-
const ms = require(
|
|
28
|
-
const Bluebird = require(
|
|
29
|
-
const semver = require(
|
|
30
|
-
|
|
31
|
-
const debug = require(
|
|
32
|
-
const ESWrapper = require(
|
|
33
|
-
const QueryTranslator = require(
|
|
34
|
-
const didYouMean = require(
|
|
35
|
-
const Service = require(
|
|
36
|
-
const { assertIsObject } = require(
|
|
37
|
-
const kerror = require(
|
|
38
|
-
const { isPlainObject } = require(
|
|
39
|
-
const scopeEnum = require(
|
|
40
|
-
const extractFields = require(
|
|
41
|
-
const { Mutex } = require(
|
|
42
|
-
const { randomNumber } = require(
|
|
43
|
-
|
|
44
|
-
const SCROLL_CACHE_PREFIX =
|
|
45
|
-
|
|
46
|
-
const ROOT_MAPPING_PROPERTIES = [
|
|
47
|
-
|
|
22
|
+
"use strict";
|
|
23
|
+
|
|
24
|
+
const assert = require("assert");
|
|
25
|
+
const _ = require("lodash");
|
|
26
|
+
const { Client: StorageClient } = require("@elastic/elasticsearch");
|
|
27
|
+
const ms = require("ms");
|
|
28
|
+
const Bluebird = require("bluebird");
|
|
29
|
+
const semver = require("semver");
|
|
30
|
+
|
|
31
|
+
const debug = require("../../util/debug")("kuzzle:services:elasticsearch");
|
|
32
|
+
const ESWrapper = require("./esWrapper");
|
|
33
|
+
const QueryTranslator = require("./queryTranslator");
|
|
34
|
+
const didYouMean = require("../../util/didYouMean");
|
|
35
|
+
const Service = require("../service");
|
|
36
|
+
const { assertIsObject } = require("../../util/requestAssertions");
|
|
37
|
+
const kerror = require("../../kerror").wrap("services", "storage");
|
|
38
|
+
const { isPlainObject } = require("../../util/safeObject");
|
|
39
|
+
const scopeEnum = require("../../core/storage/storeScopeEnum");
|
|
40
|
+
const extractFields = require("../../util/extractFields");
|
|
41
|
+
const { Mutex } = require("../../util/mutex");
|
|
42
|
+
const { randomNumber } = require("../../util/name-generator");
|
|
43
|
+
|
|
44
|
+
const SCROLL_CACHE_PREFIX = "_docscroll_";
|
|
45
|
+
|
|
46
|
+
const ROOT_MAPPING_PROPERTIES = [
|
|
47
|
+
"properties",
|
|
48
|
+
"_meta",
|
|
49
|
+
"dynamic",
|
|
50
|
+
"dynamic_templates",
|
|
51
|
+
];
|
|
52
|
+
const CHILD_MAPPING_PROPERTIES = ["type"];
|
|
48
53
|
|
|
49
54
|
// Used for collection emulation
|
|
50
|
-
const HIDDEN_COLLECTION =
|
|
51
|
-
const ALIAS_PREFIX =
|
|
52
|
-
const PRIVATE_PREFIX =
|
|
53
|
-
const PUBLIC_PREFIX =
|
|
55
|
+
const HIDDEN_COLLECTION = "_kuzzle_keep";
|
|
56
|
+
const ALIAS_PREFIX = "@"; // @todo next major release: Add ALIAS_PREFIX in FORBIDDEN_CHARS
|
|
57
|
+
const PRIVATE_PREFIX = "%";
|
|
58
|
+
const PUBLIC_PREFIX = "&";
|
|
54
59
|
const INDEX_PREFIX_POSITION_IN_INDICE = 0;
|
|
55
60
|
const INDEX_PREFIX_POSITION_IN_ALIAS = 1;
|
|
56
|
-
const NAME_SEPARATOR =
|
|
61
|
+
const NAME_SEPARATOR = ".";
|
|
57
62
|
const FORBIDDEN_CHARS = `\\/*?"<>| \t\r\n,+#:${NAME_SEPARATOR}${PUBLIC_PREFIX}${PRIVATE_PREFIX}`;
|
|
58
|
-
const DYNAMIC_PROPERTY_VALUES = [
|
|
63
|
+
const DYNAMIC_PROPERTY_VALUES = ["true", "false", "strict"];
|
|
59
64
|
|
|
60
65
|
// used to check whether we need to wait for ES to initialize or not
|
|
61
66
|
const esStateEnum = Object.freeze({
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
AWAITING: 1,
|
|
68
|
+
NONE: 2,
|
|
69
|
+
OK: 3,
|
|
65
70
|
});
|
|
66
71
|
let esState = esStateEnum.NONE;
|
|
67
72
|
|
|
@@ -77,10 +82,10 @@ class ElasticSearch extends Service {
|
|
|
77
82
|
*
|
|
78
83
|
* @returns {Object}
|
|
79
84
|
*/
|
|
80
|
-
static buildClient
|
|
85
|
+
static buildClient(config) {
|
|
81
86
|
// Passed to Elasticsearch's client to make it use
|
|
82
87
|
// Bluebird instead of ES6 promises
|
|
83
|
-
const defer = function defer
|
|
88
|
+
const defer = function defer() {
|
|
84
89
|
let resolve;
|
|
85
90
|
let reject;
|
|
86
91
|
|
|
@@ -95,13 +100,12 @@ class ElasticSearch extends Service {
|
|
|
95
100
|
return new StorageClient({ defer, ...config });
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
constructor
|
|
99
|
-
super(
|
|
103
|
+
constructor(config, scope = scopeEnum.PUBLIC) {
|
|
104
|
+
super("elasticsearch", config);
|
|
100
105
|
|
|
101
106
|
this._scope = scope;
|
|
102
|
-
this._indexPrefix =
|
|
103
|
-
? PRIVATE_PREFIX
|
|
104
|
-
: PUBLIC_PREFIX;
|
|
107
|
+
this._indexPrefix =
|
|
108
|
+
scope === scopeEnum.PRIVATE ? PRIVATE_PREFIX : PUBLIC_PREFIX;
|
|
105
109
|
|
|
106
110
|
this._client = null;
|
|
107
111
|
this._esWrapper = null;
|
|
@@ -110,36 +114,36 @@ class ElasticSearch extends Service {
|
|
|
110
114
|
|
|
111
115
|
// Allowed root key of a search query
|
|
112
116
|
this.searchBodyKeys = [
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
117
|
+
"aggregations",
|
|
118
|
+
"aggs",
|
|
119
|
+
"collapse",
|
|
120
|
+
"explain",
|
|
121
|
+
"from",
|
|
122
|
+
"highlight",
|
|
123
|
+
"query",
|
|
124
|
+
"search_after",
|
|
125
|
+
"search_timeout",
|
|
126
|
+
"size",
|
|
127
|
+
"sort",
|
|
128
|
+
"suggest",
|
|
129
|
+
"_name",
|
|
130
|
+
"_source",
|
|
131
|
+
"_source_excludes",
|
|
132
|
+
"_source_includes",
|
|
129
133
|
];
|
|
130
134
|
|
|
131
135
|
/**
|
|
132
136
|
* Only allow stored-scripts in queries
|
|
133
137
|
*/
|
|
134
|
-
this.scriptKeys = [
|
|
135
|
-
this.scriptAllowedArgs = [
|
|
138
|
+
this.scriptKeys = ["script", "_script"];
|
|
139
|
+
this.scriptAllowedArgs = ["id", "params"];
|
|
136
140
|
|
|
137
|
-
this.maxScrollDuration = this._loadMsConfig(
|
|
141
|
+
this.maxScrollDuration = this._loadMsConfig("maxScrollDuration");
|
|
138
142
|
|
|
139
|
-
this.scrollTTL = this._loadMsConfig(
|
|
143
|
+
this.scrollTTL = this._loadMsConfig("defaults.scrollTTL");
|
|
140
144
|
}
|
|
141
145
|
|
|
142
|
-
get scope
|
|
146
|
+
get scope() {
|
|
143
147
|
return this._scope;
|
|
144
148
|
}
|
|
145
149
|
|
|
@@ -149,19 +153,22 @@ class ElasticSearch extends Service {
|
|
|
149
153
|
* @override
|
|
150
154
|
* @returns {Promise}
|
|
151
155
|
*/
|
|
152
|
-
async _initSequence
|
|
156
|
+
async _initSequence() {
|
|
153
157
|
if (this._client) {
|
|
154
158
|
return;
|
|
155
159
|
}
|
|
156
160
|
|
|
157
|
-
if (
|
|
158
|
-
|
|
161
|
+
if (
|
|
162
|
+
global.NODE_ENV !== "development" &&
|
|
163
|
+
this._config.commonMapping.dynamic === "true"
|
|
159
164
|
) {
|
|
160
|
-
global.kuzzle.log.warn(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
global.kuzzle.log.warn(
|
|
166
|
+
[
|
|
167
|
+
"Your dynamic mapping policy is set to 'true' for new fields.",
|
|
168
|
+
"Elasticsearch will try to automatically infer mapping for new fields, and those cannot be changed afterward.",
|
|
169
|
+
'See the "services.storageEngine.commonMapping.dynamic" option in the kuzzlerc configuration file to change this value.',
|
|
170
|
+
].join("\n")
|
|
171
|
+
);
|
|
165
172
|
}
|
|
166
173
|
|
|
167
174
|
this._client = ElasticSearch.buildClient(this._config.client);
|
|
@@ -170,10 +177,15 @@ class ElasticSearch extends Service {
|
|
|
170
177
|
|
|
171
178
|
this._esWrapper = new ESWrapper(this._client);
|
|
172
179
|
|
|
173
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
body: { version },
|
|
182
|
+
} = await this._client.info();
|
|
174
183
|
|
|
175
|
-
if (
|
|
176
|
-
|
|
184
|
+
if (
|
|
185
|
+
version &&
|
|
186
|
+
!semver.satisfies(semver.coerce(version.number), ">= 7.0.0")
|
|
187
|
+
) {
|
|
188
|
+
throw kerror.get("version_mismatch", version.number);
|
|
177
189
|
}
|
|
178
190
|
|
|
179
191
|
this._esVersion = version;
|
|
@@ -185,7 +197,7 @@ class ElasticSearch extends Service {
|
|
|
185
197
|
* @param {Object} filters - Set of valid Koncorde filters
|
|
186
198
|
* @returns {Object} Equivalent Elasticsearch query
|
|
187
199
|
*/
|
|
188
|
-
translateKoncordeFilters
|
|
200
|
+
translateKoncordeFilters(filters) {
|
|
189
201
|
return this._translator.translate(filters);
|
|
190
202
|
}
|
|
191
203
|
|
|
@@ -195,13 +207,14 @@ class ElasticSearch extends Service {
|
|
|
195
207
|
*
|
|
196
208
|
* @returns {Promise.<Object>} service informations
|
|
197
209
|
*/
|
|
198
|
-
info
|
|
210
|
+
info() {
|
|
199
211
|
const result = {
|
|
200
|
-
type:
|
|
201
|
-
version: this._esVersion
|
|
212
|
+
type: "elasticsearch",
|
|
213
|
+
version: this._esVersion,
|
|
202
214
|
};
|
|
203
215
|
|
|
204
|
-
return this._client
|
|
216
|
+
return this._client
|
|
217
|
+
.info()
|
|
205
218
|
.then(({ body }) => {
|
|
206
219
|
result.version = body.version.number;
|
|
207
220
|
result.lucene = body.version.lucene_version;
|
|
@@ -219,7 +232,7 @@ class ElasticSearch extends Service {
|
|
|
219
232
|
|
|
220
233
|
return result;
|
|
221
234
|
})
|
|
222
|
-
.catch(error => this._esWrapper.reject(error));
|
|
235
|
+
.catch((error) => this._esWrapper.reject(error));
|
|
223
236
|
}
|
|
224
237
|
|
|
225
238
|
/**
|
|
@@ -227,9 +240,9 @@ class ElasticSearch extends Service {
|
|
|
227
240
|
*
|
|
228
241
|
* @returns {Promise.<Object>}
|
|
229
242
|
*/
|
|
230
|
-
async stats
|
|
243
|
+
async stats() {
|
|
231
244
|
const esRequest = {
|
|
232
|
-
metric: [
|
|
245
|
+
metric: ["docs", "store"],
|
|
233
246
|
};
|
|
234
247
|
|
|
235
248
|
const { body } = await this._client.indices.stats(esRequest);
|
|
@@ -238,8 +251,10 @@ class ElasticSearch extends Service {
|
|
|
238
251
|
|
|
239
252
|
for (const [indice, indiceInfo] of Object.entries(body.indices)) {
|
|
240
253
|
// Ignore non-Kuzzle indices
|
|
241
|
-
if (
|
|
242
|
-
|
|
254
|
+
if (
|
|
255
|
+
indice[INDEX_PREFIX_POSITION_IN_INDICE] !== PRIVATE_PREFIX &&
|
|
256
|
+
indice[INDEX_PREFIX_POSITION_IN_INDICE] !== PUBLIC_PREFIX
|
|
257
|
+
) {
|
|
243
258
|
continue;
|
|
244
259
|
}
|
|
245
260
|
|
|
@@ -248,12 +263,14 @@ class ElasticSearch extends Service {
|
|
|
248
263
|
const indexName = this._extractIndex(alias);
|
|
249
264
|
const collectionName = this._extractCollection(alias);
|
|
250
265
|
|
|
251
|
-
if (
|
|
252
|
-
|
|
266
|
+
if (
|
|
267
|
+
alias[INDEX_PREFIX_POSITION_IN_ALIAS] !== this._indexPrefix ||
|
|
268
|
+
collectionName === HIDDEN_COLLECTION
|
|
269
|
+
) {
|
|
253
270
|
continue;
|
|
254
271
|
}
|
|
255
272
|
|
|
256
|
-
if (!
|
|
273
|
+
if (!indexes[indexName]) {
|
|
257
274
|
indexes[indexName] = {
|
|
258
275
|
collections: [],
|
|
259
276
|
name: indexName,
|
|
@@ -285,29 +302,33 @@ class ElasticSearch extends Service {
|
|
|
285
302
|
*
|
|
286
303
|
* @returns {Promise.<{ scrollId, hits, aggregations, total }>}
|
|
287
304
|
*/
|
|
288
|
-
async scroll
|
|
305
|
+
async scroll(scrollId, { scrollTTL } = {}) {
|
|
289
306
|
const _scrollTTL = scrollTTL || this._config.defaults.scrollTTL;
|
|
290
307
|
const esRequest = {
|
|
291
308
|
scroll: _scrollTTL,
|
|
292
309
|
scrollId,
|
|
293
310
|
};
|
|
294
311
|
|
|
295
|
-
const cacheKey =
|
|
312
|
+
const cacheKey =
|
|
313
|
+
SCROLL_CACHE_PREFIX + global.kuzzle.hash(esRequest.scrollId);
|
|
296
314
|
|
|
297
|
-
debug(
|
|
315
|
+
debug("Scroll: %o", esRequest);
|
|
298
316
|
|
|
299
317
|
if (_scrollTTL) {
|
|
300
318
|
const scrollDuration = ms(_scrollTTL);
|
|
301
319
|
|
|
302
320
|
if (scrollDuration > this.maxScrollDuration) {
|
|
303
|
-
throw kerror.get(
|
|
321
|
+
throw kerror.get("scroll_duration_too_great", _scrollTTL);
|
|
304
322
|
}
|
|
305
323
|
}
|
|
306
324
|
|
|
307
|
-
const stringifiedScrollInfo = await global.kuzzle.ask(
|
|
325
|
+
const stringifiedScrollInfo = await global.kuzzle.ask(
|
|
326
|
+
"core:cache:internal:get",
|
|
327
|
+
cacheKey
|
|
328
|
+
);
|
|
308
329
|
|
|
309
|
-
if (!
|
|
310
|
-
throw kerror.get(
|
|
330
|
+
if (!stringifiedScrollInfo) {
|
|
331
|
+
throw kerror.get("unknown_scroll_id");
|
|
311
332
|
}
|
|
312
333
|
|
|
313
334
|
const scrollInfo = JSON.parse(stringifiedScrollInfo);
|
|
@@ -318,25 +339,24 @@ class ElasticSearch extends Service {
|
|
|
318
339
|
scrollInfo.fetched += body.hits.hits.length;
|
|
319
340
|
|
|
320
341
|
if (scrollInfo.fetched >= body.hits.total.value) {
|
|
321
|
-
debug(
|
|
322
|
-
await global.kuzzle.ask(
|
|
342
|
+
debug("Last scroll page fetched: deleting scroll %s", body._scroll_id);
|
|
343
|
+
await global.kuzzle.ask("core:cache:internal:del", cacheKey);
|
|
323
344
|
await this.clearScroll(body._scroll_id);
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
345
|
+
} else {
|
|
326
346
|
await global.kuzzle.ask(
|
|
327
|
-
|
|
347
|
+
"core:cache:internal:store",
|
|
328
348
|
cacheKey,
|
|
329
349
|
JSON.stringify(scrollInfo),
|
|
330
350
|
{
|
|
331
351
|
ttl: ms(_scrollTTL) || this.scrollTTL,
|
|
332
|
-
}
|
|
352
|
+
}
|
|
353
|
+
);
|
|
333
354
|
}
|
|
334
355
|
|
|
335
356
|
body.remaining = body.hits.total.value - scrollInfo.fetched;
|
|
336
357
|
|
|
337
358
|
return await this._formatSearchResult(body, scrollInfo);
|
|
338
|
-
}
|
|
339
|
-
catch (error) {
|
|
359
|
+
} catch (error) {
|
|
340
360
|
throw this._esWrapper.formatESError(error);
|
|
341
361
|
}
|
|
342
362
|
}
|
|
@@ -351,7 +371,7 @@ class ElasticSearch extends Service {
|
|
|
351
371
|
*
|
|
352
372
|
* @returns {Promise.<{ scrollId, hits, aggregations, suggest, total }>}
|
|
353
373
|
*/
|
|
354
|
-
async search
|
|
374
|
+
async search(
|
|
355
375
|
{ index, collection, searchBody, targets } = {},
|
|
356
376
|
{ from, size, scroll } = {}
|
|
357
377
|
) {
|
|
@@ -367,9 +387,8 @@ class ElasticSearch extends Service {
|
|
|
367
387
|
}
|
|
368
388
|
}
|
|
369
389
|
|
|
370
|
-
esIndexes = Array.from(indexes).join(
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
390
|
+
esIndexes = Array.from(indexes).join(",");
|
|
391
|
+
} else {
|
|
373
392
|
esIndexes = this._getAlias(index, collection);
|
|
374
393
|
}
|
|
375
394
|
|
|
@@ -386,29 +405,31 @@ class ElasticSearch extends Service {
|
|
|
386
405
|
const scrollDuration = ms(scroll);
|
|
387
406
|
|
|
388
407
|
if (scrollDuration > this.maxScrollDuration) {
|
|
389
|
-
throw kerror.get(
|
|
408
|
+
throw kerror.get("scroll_duration_too_great", scroll);
|
|
390
409
|
}
|
|
391
410
|
}
|
|
392
411
|
|
|
393
|
-
debug(
|
|
412
|
+
debug("Search: %j", esRequest);
|
|
394
413
|
|
|
395
414
|
try {
|
|
396
415
|
const { body } = await this._client.search(esRequest);
|
|
397
416
|
|
|
398
417
|
if (body._scroll_id) {
|
|
399
|
-
const ttl =
|
|
400
|
-
|
|
418
|
+
const ttl =
|
|
419
|
+
(esRequest.scroll && ms(esRequest.scroll)) ||
|
|
420
|
+
ms(this._config.defaults.scrollTTL);
|
|
401
421
|
|
|
402
422
|
await global.kuzzle.ask(
|
|
403
|
-
|
|
423
|
+
"core:cache:internal:store",
|
|
404
424
|
SCROLL_CACHE_PREFIX + global.kuzzle.hash(body._scroll_id),
|
|
405
425
|
JSON.stringify({
|
|
406
426
|
collection,
|
|
407
427
|
fetched: body.hits.hits.length,
|
|
408
428
|
index,
|
|
409
|
-
targets
|
|
429
|
+
targets,
|
|
410
430
|
}),
|
|
411
|
-
{ ttl }
|
|
431
|
+
{ ttl }
|
|
432
|
+
);
|
|
412
433
|
|
|
413
434
|
body.remaining = body.hits.total.value - body.hits.hits.length;
|
|
414
435
|
}
|
|
@@ -416,27 +437,26 @@ class ElasticSearch extends Service {
|
|
|
416
437
|
return await this._formatSearchResult(body, {
|
|
417
438
|
collection,
|
|
418
439
|
index,
|
|
419
|
-
targets
|
|
440
|
+
targets,
|
|
420
441
|
});
|
|
421
|
-
}
|
|
422
|
-
catch (error) {
|
|
442
|
+
} catch (error) {
|
|
423
443
|
throw this._esWrapper.formatESError(error);
|
|
424
444
|
}
|
|
425
445
|
}
|
|
426
446
|
|
|
427
447
|
/**
|
|
428
448
|
* Generate a map that associate an alias to a pair of index and collection
|
|
429
|
-
*
|
|
430
|
-
* @param {*} targets
|
|
431
|
-
* @returns
|
|
449
|
+
*
|
|
450
|
+
* @param {*} targets
|
|
451
|
+
* @returns
|
|
432
452
|
*/
|
|
433
|
-
_mapTargetsToAlias
|
|
453
|
+
_mapTargetsToAlias(targets) {
|
|
434
454
|
const aliasToTargets = {};
|
|
435
455
|
|
|
436
456
|
for (const target of targets) {
|
|
437
457
|
for (const targetCollection of target.collections) {
|
|
438
458
|
const alias = this._getAlias(target.index, targetCollection);
|
|
439
|
-
if (!
|
|
459
|
+
if (!aliasToTargets[alias]) {
|
|
440
460
|
aliasToTargets[alias] = {
|
|
441
461
|
collection: targetCollection,
|
|
442
462
|
index: target.index,
|
|
@@ -448,7 +468,7 @@ class ElasticSearch extends Service {
|
|
|
448
468
|
return aliasToTargets;
|
|
449
469
|
}
|
|
450
470
|
|
|
451
|
-
async _formatSearchResult
|
|
471
|
+
async _formatSearchResult(body, searchInfo = {}) {
|
|
452
472
|
let aliasToTargets = {};
|
|
453
473
|
const aliasCache = new Map();
|
|
454
474
|
|
|
@@ -470,10 +490,9 @@ class ElasticSearch extends Service {
|
|
|
470
490
|
* retrieve the appropriate index and collection based on the alias
|
|
471
491
|
*/
|
|
472
492
|
if (hit._index && searchInfo.targets) {
|
|
473
|
-
|
|
474
493
|
// Caching to reduce call to ES
|
|
475
494
|
let aliases = aliasCache.get(hit._index);
|
|
476
|
-
if (!
|
|
495
|
+
if (!aliases) {
|
|
477
496
|
// Retrieve all the alias associated to one index
|
|
478
497
|
aliases = await this._getAliasFromIndice(hit._index);
|
|
479
498
|
aliasCache.set(hit._index, aliases);
|
|
@@ -484,7 +503,7 @@ class ElasticSearch extends Service {
|
|
|
484
503
|
* find the first alias that exists in the map of aliases associated
|
|
485
504
|
* to the targets.
|
|
486
505
|
*/
|
|
487
|
-
const alias = aliases.find(_alias => aliasToTargets[_alias]);
|
|
506
|
+
const alias = aliases.find((_alias) => aliasToTargets[_alias]);
|
|
488
507
|
// Retrieve index and collection information based on the matching alias
|
|
489
508
|
index = aliasToTargets[alias].index;
|
|
490
509
|
collection = aliasToTargets[alias].collection;
|
|
@@ -500,21 +519,24 @@ class ElasticSearch extends Service {
|
|
|
500
519
|
};
|
|
501
520
|
};
|
|
502
521
|
|
|
503
|
-
async function formatInnerHits
|
|
504
|
-
if (!
|
|
522
|
+
async function formatInnerHits(innerHits) {
|
|
523
|
+
if (!innerHits) {
|
|
505
524
|
return undefined;
|
|
506
525
|
}
|
|
507
526
|
|
|
508
527
|
const formattedInnerHits = {};
|
|
509
528
|
for (const [name, innerHit] of Object.entries(innerHits)) {
|
|
510
|
-
formattedInnerHits[name] = await Bluebird.map(
|
|
529
|
+
formattedInnerHits[name] = await Bluebird.map(
|
|
530
|
+
innerHit.hits.hits,
|
|
531
|
+
formatHit
|
|
532
|
+
);
|
|
511
533
|
}
|
|
512
534
|
return formattedInnerHits;
|
|
513
535
|
}
|
|
514
536
|
|
|
515
|
-
const hits = await Bluebird.map(body.hits.hits, async hit => ({
|
|
537
|
+
const hits = await Bluebird.map(body.hits.hits, async (hit) => ({
|
|
516
538
|
inner_hits: await formatInnerHits(hit.inner_hits),
|
|
517
|
-
...await formatHit(hit)
|
|
539
|
+
...(await formatHit(hit)),
|
|
518
540
|
}));
|
|
519
541
|
|
|
520
542
|
return {
|
|
@@ -536,20 +558,20 @@ class ElasticSearch extends Service {
|
|
|
536
558
|
*
|
|
537
559
|
* @returns {Promise.<{ _id, _version, _source }>}
|
|
538
560
|
*/
|
|
539
|
-
async get
|
|
561
|
+
async get(index, collection, id) {
|
|
540
562
|
const esRequest = {
|
|
541
563
|
id,
|
|
542
|
-
index: this._getAlias(index, collection)
|
|
564
|
+
index: this._getAlias(index, collection),
|
|
543
565
|
};
|
|
544
566
|
|
|
545
567
|
// Just in case the user make a GET on url /mainindex/test/_search
|
|
546
568
|
// Without this test we return something weird: a result.hits.hits with all
|
|
547
569
|
// document without filter because the body is empty in HTTP by default
|
|
548
|
-
if (esRequest.id ===
|
|
549
|
-
return kerror.reject(
|
|
570
|
+
if (esRequest.id === "_search") {
|
|
571
|
+
return kerror.reject("search_as_an_id");
|
|
550
572
|
}
|
|
551
573
|
|
|
552
|
-
debug(
|
|
574
|
+
debug("Get document: %o", esRequest);
|
|
553
575
|
|
|
554
576
|
try {
|
|
555
577
|
const { body } = await this._client.get(esRequest);
|
|
@@ -557,10 +579,9 @@ class ElasticSearch extends Service {
|
|
|
557
579
|
return {
|
|
558
580
|
_id: body._id,
|
|
559
581
|
_source: body._source,
|
|
560
|
-
_version: body._version
|
|
582
|
+
_version: body._version,
|
|
561
583
|
};
|
|
562
|
-
}
|
|
563
|
-
catch (error) {
|
|
584
|
+
} catch (error) {
|
|
564
585
|
throw this._esWrapper.formatESError(error);
|
|
565
586
|
}
|
|
566
587
|
}
|
|
@@ -576,31 +597,32 @@ class ElasticSearch extends Service {
|
|
|
576
597
|
*
|
|
577
598
|
* @returns {Promise.<{ items: Array<{ _id, _source, _version }>, errors }>}
|
|
578
599
|
*/
|
|
579
|
-
async mGet
|
|
600
|
+
async mGet(index, collection, ids) {
|
|
580
601
|
if (ids.length === 0) {
|
|
581
602
|
return { errors: [], item: [] };
|
|
582
603
|
}
|
|
583
604
|
|
|
584
605
|
const esRequest = {
|
|
585
606
|
body: {
|
|
586
|
-
docs: ids.map(_id => ({
|
|
587
|
-
|
|
607
|
+
docs: ids.map((_id) => ({
|
|
608
|
+
_id,
|
|
609
|
+
_index: this._getAlias(index, collection),
|
|
610
|
+
})),
|
|
611
|
+
},
|
|
588
612
|
};
|
|
589
613
|
|
|
590
|
-
debug(
|
|
614
|
+
debug("Multi-get documents: %o", esRequest);
|
|
591
615
|
|
|
592
616
|
let body;
|
|
593
617
|
|
|
594
618
|
try {
|
|
595
619
|
({ body } = await this._client.mget(esRequest)); // NOSONAR
|
|
596
|
-
}
|
|
597
|
-
catch (e) {
|
|
620
|
+
} catch (e) {
|
|
598
621
|
throw this._esWrapper.formatESError(e);
|
|
599
622
|
}
|
|
600
623
|
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
items = [];
|
|
624
|
+
const errors = [];
|
|
625
|
+
const items = [];
|
|
604
626
|
|
|
605
627
|
for (let i = 0; i < body.docs.length; i++) {
|
|
606
628
|
const doc = body.docs[i];
|
|
@@ -609,10 +631,9 @@ class ElasticSearch extends Service {
|
|
|
609
631
|
items.push({
|
|
610
632
|
_id: doc._id,
|
|
611
633
|
_source: doc._source,
|
|
612
|
-
_version: doc._version
|
|
634
|
+
_version: doc._version,
|
|
613
635
|
});
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
636
|
+
} else {
|
|
616
637
|
errors.push(doc._id);
|
|
617
638
|
}
|
|
618
639
|
}
|
|
@@ -629,19 +650,18 @@ class ElasticSearch extends Service {
|
|
|
629
650
|
*
|
|
630
651
|
* @returns {Promise.<Number>} count
|
|
631
652
|
*/
|
|
632
|
-
async count
|
|
653
|
+
async count(index, collection, searchBody = {}) {
|
|
633
654
|
const esRequest = {
|
|
634
655
|
body: this._sanitizeSearchBody(searchBody),
|
|
635
|
-
index: this._getAlias(index, collection)
|
|
656
|
+
index: this._getAlias(index, collection),
|
|
636
657
|
};
|
|
637
658
|
|
|
638
|
-
debug(
|
|
659
|
+
debug("Count: %o", esRequest);
|
|
639
660
|
|
|
640
661
|
try {
|
|
641
662
|
const { body } = await this._client.count(esRequest);
|
|
642
663
|
return body.count;
|
|
643
|
-
}
|
|
644
|
-
catch (error) {
|
|
664
|
+
} catch (error) {
|
|
645
665
|
throw this._esWrapper.formatESError(error);
|
|
646
666
|
}
|
|
647
667
|
}
|
|
@@ -657,19 +677,20 @@ class ElasticSearch extends Service {
|
|
|
657
677
|
*
|
|
658
678
|
* @returns {Promise.<Object>} { _id, _version, _source }
|
|
659
679
|
*/
|
|
660
|
-
async create
|
|
680
|
+
async create(
|
|
661
681
|
index,
|
|
662
682
|
collection,
|
|
663
683
|
content,
|
|
664
|
-
{ id, refresh, userId = null } = {}
|
|
684
|
+
{ id, refresh, userId = null } = {}
|
|
685
|
+
) {
|
|
665
686
|
assertIsObject(content);
|
|
666
687
|
|
|
667
688
|
const esRequest = {
|
|
668
689
|
body: content,
|
|
669
690
|
id,
|
|
670
691
|
index: this._getAlias(index, collection),
|
|
671
|
-
op_type: id ?
|
|
672
|
-
refresh
|
|
692
|
+
op_type: id ? "create" : "index",
|
|
693
|
+
refresh,
|
|
673
694
|
};
|
|
674
695
|
|
|
675
696
|
assertNoRouting(esRequest);
|
|
@@ -680,10 +701,10 @@ class ElasticSearch extends Service {
|
|
|
680
701
|
author: getKuid(userId),
|
|
681
702
|
createdAt: Date.now(),
|
|
682
703
|
updatedAt: null,
|
|
683
|
-
updater: null
|
|
704
|
+
updater: null,
|
|
684
705
|
};
|
|
685
706
|
|
|
686
|
-
debug(
|
|
707
|
+
debug("Create document: %o", esRequest);
|
|
687
708
|
|
|
688
709
|
try {
|
|
689
710
|
const { body } = await this._client.index(esRequest);
|
|
@@ -691,10 +712,9 @@ class ElasticSearch extends Service {
|
|
|
691
712
|
return {
|
|
692
713
|
_id: body._id,
|
|
693
714
|
_source: esRequest.body,
|
|
694
|
-
_version: body._version
|
|
715
|
+
_version: body._version,
|
|
695
716
|
};
|
|
696
|
-
}
|
|
697
|
-
catch (error) {
|
|
717
|
+
} catch (error) {
|
|
698
718
|
throw this._esWrapper.formatESError(error);
|
|
699
719
|
}
|
|
700
720
|
}
|
|
@@ -710,17 +730,18 @@ class ElasticSearch extends Service {
|
|
|
710
730
|
*
|
|
711
731
|
* @returns {Promise.<Object>} { _id, _version, _source, created }
|
|
712
732
|
*/
|
|
713
|
-
async createOrReplace
|
|
733
|
+
async createOrReplace(
|
|
714
734
|
index,
|
|
715
735
|
collection,
|
|
716
736
|
id,
|
|
717
737
|
content,
|
|
718
|
-
{ refresh, userId = null, injectKuzzleMeta = true } = {}
|
|
738
|
+
{ refresh, userId = null, injectKuzzleMeta = true } = {}
|
|
739
|
+
) {
|
|
719
740
|
const esRequest = {
|
|
720
741
|
body: content,
|
|
721
742
|
id,
|
|
722
743
|
index: this._getAlias(index, collection),
|
|
723
|
-
refresh
|
|
744
|
+
refresh,
|
|
724
745
|
};
|
|
725
746
|
|
|
726
747
|
assertNoRouting(esRequest);
|
|
@@ -732,11 +753,11 @@ class ElasticSearch extends Service {
|
|
|
732
753
|
author: getKuid(userId),
|
|
733
754
|
createdAt: Date.now(),
|
|
734
755
|
updatedAt: Date.now(),
|
|
735
|
-
updater: getKuid(userId)
|
|
756
|
+
updater: getKuid(userId),
|
|
736
757
|
};
|
|
737
758
|
}
|
|
738
759
|
|
|
739
|
-
debug(
|
|
760
|
+
debug("Create or replace document: %o", esRequest);
|
|
740
761
|
|
|
741
762
|
try {
|
|
742
763
|
const { body } = await this._client.index(esRequest);
|
|
@@ -745,10 +766,9 @@ class ElasticSearch extends Service {
|
|
|
745
766
|
_id: body._id,
|
|
746
767
|
_source: esRequest.body,
|
|
747
768
|
_version: body._version,
|
|
748
|
-
created: body.result ===
|
|
769
|
+
created: body.result === "created", // Needed by the notifier
|
|
749
770
|
};
|
|
750
|
-
}
|
|
751
|
-
catch (error) {
|
|
771
|
+
} catch (error) {
|
|
752
772
|
throw this._esWrapper.formatESError(error);
|
|
753
773
|
}
|
|
754
774
|
}
|
|
@@ -764,19 +784,21 @@ class ElasticSearch extends Service {
|
|
|
764
784
|
*
|
|
765
785
|
* @returns {Promise.<{ _id, _version }>}
|
|
766
786
|
*/
|
|
767
|
-
async update
|
|
787
|
+
async update(
|
|
768
788
|
index,
|
|
769
789
|
collection,
|
|
770
790
|
id,
|
|
771
791
|
content,
|
|
772
|
-
{ refresh, userId = null, retryOnConflict } = {}
|
|
792
|
+
{ refresh, userId = null, retryOnConflict } = {}
|
|
793
|
+
) {
|
|
773
794
|
const esRequest = {
|
|
774
795
|
_source: true,
|
|
775
796
|
body: { doc: content },
|
|
776
797
|
id,
|
|
777
798
|
index: this._getAlias(index, collection),
|
|
778
799
|
refresh,
|
|
779
|
-
retry_on_conflict:
|
|
800
|
+
retry_on_conflict:
|
|
801
|
+
retryOnConflict || this._config.defaults.onUpdateConflictRetries,
|
|
780
802
|
};
|
|
781
803
|
|
|
782
804
|
assertNoRouting(esRequest);
|
|
@@ -785,20 +807,19 @@ class ElasticSearch extends Service {
|
|
|
785
807
|
// Add metadata
|
|
786
808
|
esRequest.body.doc._kuzzle_info = {
|
|
787
809
|
updatedAt: Date.now(),
|
|
788
|
-
updater: getKuid(userId)
|
|
810
|
+
updater: getKuid(userId),
|
|
789
811
|
};
|
|
790
812
|
|
|
791
|
-
debug(
|
|
813
|
+
debug("Update document: %o", esRequest);
|
|
792
814
|
|
|
793
815
|
try {
|
|
794
816
|
const { body } = await this._client.update(esRequest);
|
|
795
817
|
return {
|
|
796
818
|
_id: body._id,
|
|
797
819
|
_source: body.get._source,
|
|
798
|
-
_version: body._version
|
|
820
|
+
_version: body._version,
|
|
799
821
|
};
|
|
800
|
-
}
|
|
801
|
-
catch (error) {
|
|
822
|
+
} catch (error) {
|
|
802
823
|
throw this._esWrapper.formatESError(error);
|
|
803
824
|
}
|
|
804
825
|
}
|
|
@@ -815,12 +836,13 @@ class ElasticSearch extends Service {
|
|
|
815
836
|
*
|
|
816
837
|
* @returns {Promise.<{ _id, _version }>}
|
|
817
838
|
*/
|
|
818
|
-
async upsert
|
|
839
|
+
async upsert(
|
|
819
840
|
index,
|
|
820
841
|
collection,
|
|
821
842
|
id,
|
|
822
843
|
content,
|
|
823
|
-
{ defaultValues = {}, refresh, userId = null, retryOnConflict } = {}
|
|
844
|
+
{ defaultValues = {}, refresh, userId = null, retryOnConflict } = {}
|
|
845
|
+
) {
|
|
824
846
|
const esRequest = {
|
|
825
847
|
_source: true,
|
|
826
848
|
body: {
|
|
@@ -830,7 +852,8 @@ class ElasticSearch extends Service {
|
|
|
830
852
|
id,
|
|
831
853
|
index: this._getAlias(index, collection),
|
|
832
854
|
refresh,
|
|
833
|
-
retry_on_conflict:
|
|
855
|
+
retry_on_conflict:
|
|
856
|
+
retryOnConflict || this._config.defaults.onUpdateConflictRetries,
|
|
834
857
|
};
|
|
835
858
|
|
|
836
859
|
assertNoRouting(esRequest);
|
|
@@ -849,7 +872,7 @@ class ElasticSearch extends Service {
|
|
|
849
872
|
createdAt: now,
|
|
850
873
|
};
|
|
851
874
|
|
|
852
|
-
debug(
|
|
875
|
+
debug("Upsert document: %o", esRequest);
|
|
853
876
|
|
|
854
877
|
try {
|
|
855
878
|
const { body } = await this._client.update(esRequest);
|
|
@@ -858,10 +881,9 @@ class ElasticSearch extends Service {
|
|
|
858
881
|
_id: body._id,
|
|
859
882
|
_source: body.get._source,
|
|
860
883
|
_version: body._version,
|
|
861
|
-
created: body.result ===
|
|
884
|
+
created: body.result === "created",
|
|
862
885
|
};
|
|
863
|
-
}
|
|
864
|
-
catch (error) {
|
|
886
|
+
} catch (error) {
|
|
865
887
|
throw this._esWrapper.formatESError(error);
|
|
866
888
|
}
|
|
867
889
|
}
|
|
@@ -877,18 +899,19 @@ class ElasticSearch extends Service {
|
|
|
877
899
|
*
|
|
878
900
|
* @returns {Promise.<{ _id, _version, _source }>}
|
|
879
901
|
*/
|
|
880
|
-
async replace
|
|
902
|
+
async replace(
|
|
881
903
|
index,
|
|
882
904
|
collection,
|
|
883
905
|
id,
|
|
884
906
|
content,
|
|
885
|
-
{ refresh, userId = null } = {}
|
|
907
|
+
{ refresh, userId = null } = {}
|
|
908
|
+
) {
|
|
886
909
|
const alias = this._getAlias(index, collection);
|
|
887
910
|
const esRequest = {
|
|
888
911
|
body: content,
|
|
889
912
|
id,
|
|
890
913
|
index: alias,
|
|
891
|
-
refresh
|
|
914
|
+
refresh,
|
|
892
915
|
};
|
|
893
916
|
|
|
894
917
|
assertNoRouting(esRequest);
|
|
@@ -899,27 +922,26 @@ class ElasticSearch extends Service {
|
|
|
899
922
|
author: getKuid(userId),
|
|
900
923
|
createdAt: Date.now(),
|
|
901
924
|
updatedAt: Date.now(),
|
|
902
|
-
updater: getKuid(userId)
|
|
925
|
+
updater: getKuid(userId),
|
|
903
926
|
};
|
|
904
927
|
|
|
905
928
|
try {
|
|
906
929
|
const { body: exists } = await this._client.exists({ id, index: alias });
|
|
907
930
|
|
|
908
|
-
if (!
|
|
909
|
-
throw kerror.get(
|
|
931
|
+
if (!exists) {
|
|
932
|
+
throw kerror.get("not_found", id, index, collection);
|
|
910
933
|
}
|
|
911
934
|
|
|
912
|
-
debug(
|
|
935
|
+
debug("Replace document: %o", esRequest);
|
|
913
936
|
|
|
914
937
|
const { body } = await this._client.index(esRequest);
|
|
915
938
|
|
|
916
939
|
return {
|
|
917
940
|
_id: id,
|
|
918
941
|
_source: esRequest.body,
|
|
919
|
-
_version: body._version
|
|
942
|
+
_version: body._version,
|
|
920
943
|
};
|
|
921
|
-
}
|
|
922
|
-
catch (error) {
|
|
944
|
+
} catch (error) {
|
|
923
945
|
throw this._esWrapper.formatESError(error);
|
|
924
946
|
}
|
|
925
947
|
}
|
|
@@ -934,25 +956,20 @@ class ElasticSearch extends Service {
|
|
|
934
956
|
*
|
|
935
957
|
* @returns {Promise}
|
|
936
958
|
*/
|
|
937
|
-
async delete
|
|
938
|
-
index,
|
|
939
|
-
collection,
|
|
940
|
-
id,
|
|
941
|
-
{ refresh } = {}) {
|
|
959
|
+
async delete(index, collection, id, { refresh } = {}) {
|
|
942
960
|
const esRequest = {
|
|
943
961
|
id,
|
|
944
962
|
index: this._getAlias(index, collection),
|
|
945
|
-
refresh
|
|
963
|
+
refresh,
|
|
946
964
|
};
|
|
947
965
|
|
|
948
966
|
assertWellFormedRefresh(esRequest);
|
|
949
967
|
|
|
950
|
-
debug(
|
|
968
|
+
debug("Delete document: %o", esRequest);
|
|
951
969
|
|
|
952
970
|
try {
|
|
953
971
|
await this._client.delete(esRequest);
|
|
954
|
-
}
|
|
955
|
-
catch (error) {
|
|
972
|
+
} catch (error) {
|
|
956
973
|
throw this._esWrapper.formatESError(error);
|
|
957
974
|
}
|
|
958
975
|
return null;
|
|
@@ -974,20 +991,21 @@ class ElasticSearch extends Service {
|
|
|
974
991
|
*
|
|
975
992
|
* @returns {Promise.<{ documents, total, deleted, failures: Array<{ _shardId, reason }> }>}
|
|
976
993
|
*/
|
|
977
|
-
async deleteByQuery
|
|
994
|
+
async deleteByQuery(
|
|
978
995
|
index,
|
|
979
996
|
collection,
|
|
980
997
|
query,
|
|
981
|
-
{ refresh, size = 1000, fetch = true } = {}
|
|
998
|
+
{ refresh, size = 1000, fetch = true } = {}
|
|
999
|
+
) {
|
|
982
1000
|
const esRequest = {
|
|
983
1001
|
body: this._sanitizeSearchBody({ query }),
|
|
984
1002
|
index: this._getAlias(index, collection),
|
|
985
|
-
scroll:
|
|
986
|
-
size
|
|
1003
|
+
scroll: "5s",
|
|
1004
|
+
size,
|
|
987
1005
|
};
|
|
988
1006
|
|
|
989
|
-
if (!
|
|
990
|
-
throw kerror.get(
|
|
1007
|
+
if (!isPlainObject(query)) {
|
|
1008
|
+
throw kerror.get("missing_argument", "body.query");
|
|
991
1009
|
}
|
|
992
1010
|
|
|
993
1011
|
try {
|
|
@@ -997,21 +1015,22 @@ class ElasticSearch extends Service {
|
|
|
997
1015
|
documents = await this._getAllDocumentsFromQuery(esRequest);
|
|
998
1016
|
}
|
|
999
1017
|
|
|
1000
|
-
debug(
|
|
1018
|
+
debug("Delete by query: %o", esRequest);
|
|
1001
1019
|
|
|
1002
|
-
esRequest.refresh = refresh ===
|
|
1020
|
+
esRequest.refresh = refresh === "wait_for" ? true : refresh;
|
|
1003
1021
|
|
|
1004
1022
|
const { body } = await this._client.deleteByQuery(esRequest);
|
|
1005
1023
|
|
|
1006
1024
|
return {
|
|
1007
1025
|
deleted: body.deleted,
|
|
1008
1026
|
documents,
|
|
1009
|
-
failures: body.failures
|
|
1010
|
-
|
|
1027
|
+
failures: body.failures.map(({ shardId, reason }) => ({
|
|
1028
|
+
reason,
|
|
1029
|
+
shardId,
|
|
1030
|
+
})),
|
|
1011
1031
|
total: body.total,
|
|
1012
1032
|
};
|
|
1013
|
-
}
|
|
1014
|
-
catch (error) {
|
|
1033
|
+
} catch (error) {
|
|
1015
1034
|
throw this._esWrapper.formatESError(error);
|
|
1016
1035
|
}
|
|
1017
1036
|
}
|
|
@@ -1027,12 +1046,13 @@ class ElasticSearch extends Service {
|
|
|
1027
1046
|
*
|
|
1028
1047
|
* @returns {Promise.<{ _id, _version, _source }>}
|
|
1029
1048
|
*/
|
|
1030
|
-
async deleteFields
|
|
1049
|
+
async deleteFields(
|
|
1031
1050
|
index,
|
|
1032
1051
|
collection,
|
|
1033
1052
|
id,
|
|
1034
1053
|
fields,
|
|
1035
|
-
{ refresh, userId = null } = {}
|
|
1054
|
+
{ refresh, userId = null } = {}
|
|
1055
|
+
) {
|
|
1036
1056
|
const alias = this._getAlias(index, collection);
|
|
1037
1057
|
const esRequest = {
|
|
1038
1058
|
id,
|
|
@@ -1040,7 +1060,7 @@ class ElasticSearch extends Service {
|
|
|
1040
1060
|
};
|
|
1041
1061
|
|
|
1042
1062
|
try {
|
|
1043
|
-
debug(
|
|
1063
|
+
debug("DeleteFields document: %o", esRequest);
|
|
1044
1064
|
const { body } = await this._client.get(esRequest);
|
|
1045
1065
|
|
|
1046
1066
|
for (const field of fields) {
|
|
@@ -1052,14 +1072,14 @@ class ElasticSearch extends Service {
|
|
|
1052
1072
|
body._source._kuzzle_info = {
|
|
1053
1073
|
...body._source._kuzzle_info,
|
|
1054
1074
|
updatedAt: Date.now(),
|
|
1055
|
-
updater: getKuid(userId)
|
|
1075
|
+
updater: getKuid(userId),
|
|
1056
1076
|
};
|
|
1057
1077
|
|
|
1058
1078
|
const newEsRequest = {
|
|
1059
1079
|
body: body._source,
|
|
1060
1080
|
id,
|
|
1061
1081
|
index: alias,
|
|
1062
|
-
refresh
|
|
1082
|
+
refresh,
|
|
1063
1083
|
};
|
|
1064
1084
|
|
|
1065
1085
|
assertNoRouting(newEsRequest);
|
|
@@ -1070,38 +1090,37 @@ class ElasticSearch extends Service {
|
|
|
1070
1090
|
return {
|
|
1071
1091
|
_id: id,
|
|
1072
1092
|
_source: body._source,
|
|
1073
|
-
_version: updated._version
|
|
1093
|
+
_version: updated._version,
|
|
1074
1094
|
};
|
|
1075
|
-
}
|
|
1076
|
-
catch (error) {
|
|
1095
|
+
} catch (error) {
|
|
1077
1096
|
throw this._esWrapper.formatESError(error);
|
|
1078
1097
|
}
|
|
1079
1098
|
}
|
|
1080
1099
|
|
|
1081
1100
|
/**
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
async updateByQuery
|
|
1101
|
+
* Updates all documents matching the provided filters
|
|
1102
|
+
*
|
|
1103
|
+
* @param {String} index - Index name
|
|
1104
|
+
* @param {String} collection - Collection name
|
|
1105
|
+
* @param {Object} query - Query to match documents
|
|
1106
|
+
* @param {Object} changes - Changes wanted on documents
|
|
1107
|
+
* @param {Object} options - refresh (undefined), size (undefined)
|
|
1108
|
+
*
|
|
1109
|
+
* @returns {Promise.<{ successes: [_id, _source, _status], errors: [ document, status, reason ] }>}
|
|
1110
|
+
*/
|
|
1111
|
+
async updateByQuery(
|
|
1093
1112
|
index,
|
|
1094
1113
|
collection,
|
|
1095
1114
|
query,
|
|
1096
1115
|
changes,
|
|
1097
|
-
{ refresh, size = 1000, userId = null } = {}
|
|
1098
|
-
|
|
1116
|
+
{ refresh, size = 1000, userId = null } = {}
|
|
1117
|
+
) {
|
|
1099
1118
|
try {
|
|
1100
1119
|
const esRequest = {
|
|
1101
1120
|
body: this._sanitizeSearchBody({ query }),
|
|
1102
1121
|
index: this._getAlias(index, collection),
|
|
1103
|
-
scroll:
|
|
1104
|
-
size
|
|
1122
|
+
scroll: "5s",
|
|
1123
|
+
size,
|
|
1105
1124
|
};
|
|
1106
1125
|
|
|
1107
1126
|
const documents = await this._getAllDocumentsFromQuery(esRequest);
|
|
@@ -1113,44 +1132,45 @@ class ElasticSearch extends Service {
|
|
|
1113
1132
|
document.body = changes;
|
|
1114
1133
|
}
|
|
1115
1134
|
|
|
1116
|
-
debug(
|
|
1135
|
+
debug("Update by query: %o", esRequest);
|
|
1117
1136
|
|
|
1118
1137
|
const { errors, items } = await this.mUpdate(
|
|
1119
1138
|
index,
|
|
1120
1139
|
collection,
|
|
1121
1140
|
documents,
|
|
1122
|
-
{ refresh, userId }
|
|
1141
|
+
{ refresh, userId }
|
|
1142
|
+
);
|
|
1123
1143
|
|
|
1124
1144
|
return {
|
|
1125
1145
|
errors,
|
|
1126
|
-
successes: items
|
|
1146
|
+
successes: items,
|
|
1127
1147
|
};
|
|
1128
|
-
}
|
|
1129
|
-
catch (error) {
|
|
1148
|
+
} catch (error) {
|
|
1130
1149
|
throw this._esWrapper.formatESError(error);
|
|
1131
1150
|
}
|
|
1132
1151
|
}
|
|
1133
1152
|
|
|
1134
1153
|
/**
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
async bulkUpdateByQuery
|
|
1154
|
+
* Updates all documents matching the provided filters
|
|
1155
|
+
*
|
|
1156
|
+
* @param {String} index - Index name
|
|
1157
|
+
* @param {String} collection - Collection name
|
|
1158
|
+
* @param {Object} query - Query to match documents
|
|
1159
|
+
* @param {Object} changes - Changes wanted on documents
|
|
1160
|
+
* @param {Object} options - refresh (undefined)
|
|
1161
|
+
*
|
|
1162
|
+
* @returns {Promise.<{ successes: [_id, _source, _status], errors: [ document, status, reason ] }>}
|
|
1163
|
+
*/
|
|
1164
|
+
async bulkUpdateByQuery(
|
|
1146
1165
|
index,
|
|
1147
1166
|
collection,
|
|
1148
1167
|
query,
|
|
1149
1168
|
changes,
|
|
1150
|
-
{ refresh =
|
|
1169
|
+
{ refresh = "false" } = {}
|
|
1170
|
+
) {
|
|
1151
1171
|
const script = {
|
|
1152
1172
|
params: {},
|
|
1153
|
-
source:
|
|
1173
|
+
source: "",
|
|
1154
1174
|
};
|
|
1155
1175
|
|
|
1156
1176
|
const flatChanges = extractFields(changes, { alsoExtractValues: true });
|
|
@@ -1166,28 +1186,29 @@ class ElasticSearch extends Service {
|
|
|
1166
1186
|
script,
|
|
1167
1187
|
},
|
|
1168
1188
|
index: this._getAlias(index, collection),
|
|
1169
|
-
refresh
|
|
1189
|
+
refresh,
|
|
1170
1190
|
};
|
|
1171
1191
|
|
|
1172
|
-
debug(
|
|
1192
|
+
debug("Bulk Update by query: %o", esRequest);
|
|
1173
1193
|
|
|
1174
1194
|
let response;
|
|
1175
1195
|
try {
|
|
1176
1196
|
response = await this._client.updateByQuery(esRequest);
|
|
1177
|
-
}
|
|
1178
|
-
catch (error) {
|
|
1197
|
+
} catch (error) {
|
|
1179
1198
|
throw this._esWrapper.formatESError(error);
|
|
1180
1199
|
}
|
|
1181
1200
|
|
|
1182
1201
|
if (response.body.failures.length) {
|
|
1183
|
-
const errors = response.body.failures
|
|
1184
|
-
|
|
1202
|
+
const errors = response.body.failures.map(({ shardId, reason }) => ({
|
|
1203
|
+
reason,
|
|
1204
|
+
shardId,
|
|
1205
|
+
}));
|
|
1185
1206
|
|
|
1186
|
-
throw kerror.get(
|
|
1207
|
+
throw kerror.get("incomplete_update", response.body.updated, errors);
|
|
1187
1208
|
}
|
|
1188
1209
|
|
|
1189
1210
|
return {
|
|
1190
|
-
updated: response.body.updated
|
|
1211
|
+
updated: response.body.updated,
|
|
1191
1212
|
};
|
|
1192
1213
|
}
|
|
1193
1214
|
|
|
@@ -1203,22 +1224,23 @@ class ElasticSearch extends Service {
|
|
|
1203
1224
|
*
|
|
1204
1225
|
* @returns {Promise.<any[]>} Array of results returned by the callback
|
|
1205
1226
|
*/
|
|
1206
|
-
async mExecute
|
|
1227
|
+
async mExecute(
|
|
1207
1228
|
index,
|
|
1208
1229
|
collection,
|
|
1209
1230
|
query,
|
|
1210
1231
|
callback,
|
|
1211
|
-
{ size = 10, scrollTTl =
|
|
1232
|
+
{ size = 10, scrollTTl = "5s" } = {}
|
|
1233
|
+
) {
|
|
1212
1234
|
const esRequest = {
|
|
1213
1235
|
body: this._sanitizeSearchBody({ query }),
|
|
1214
1236
|
from: 0,
|
|
1215
1237
|
index: this._getAlias(index, collection),
|
|
1216
1238
|
scroll: scrollTTl,
|
|
1217
|
-
size
|
|
1239
|
+
size,
|
|
1218
1240
|
};
|
|
1219
1241
|
|
|
1220
|
-
if (!
|
|
1221
|
-
throw kerror.get(
|
|
1242
|
+
if (!isPlainObject(query)) {
|
|
1243
|
+
throw kerror.get("missing_argument", "body.query");
|
|
1222
1244
|
}
|
|
1223
1245
|
|
|
1224
1246
|
const client = this._client;
|
|
@@ -1231,7 +1253,10 @@ class ElasticSearch extends Service {
|
|
|
1231
1253
|
results = await new Bluebird((resolve, reject) => {
|
|
1232
1254
|
this._client.search(
|
|
1233
1255
|
esRequest,
|
|
1234
|
-
async function getMoreUntilDone
|
|
1256
|
+
async function getMoreUntilDone(
|
|
1257
|
+
error,
|
|
1258
|
+
{ body: { hits, _scroll_id } }
|
|
1259
|
+
) {
|
|
1235
1260
|
if (error) {
|
|
1236
1261
|
reject(error);
|
|
1237
1262
|
return;
|
|
@@ -1245,18 +1270,20 @@ class ElasticSearch extends Service {
|
|
|
1245
1270
|
processed += hits.hits.length;
|
|
1246
1271
|
|
|
1247
1272
|
if (hits.total.value !== processed) {
|
|
1248
|
-
client.scroll(
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1273
|
+
client.scroll(
|
|
1274
|
+
{
|
|
1275
|
+
scroll: esRequest.scroll,
|
|
1276
|
+
scrollId: _scroll_id,
|
|
1277
|
+
},
|
|
1278
|
+
getMoreUntilDone
|
|
1279
|
+
);
|
|
1280
|
+
} else {
|
|
1254
1281
|
resolve(results);
|
|
1255
1282
|
}
|
|
1256
|
-
}
|
|
1283
|
+
}
|
|
1284
|
+
);
|
|
1257
1285
|
});
|
|
1258
|
-
}
|
|
1259
|
-
finally {
|
|
1286
|
+
} finally {
|
|
1260
1287
|
this.clearScroll(scrollId);
|
|
1261
1288
|
}
|
|
1262
1289
|
|
|
@@ -1275,15 +1302,14 @@ class ElasticSearch extends Service {
|
|
|
1275
1302
|
*
|
|
1276
1303
|
* @returns {Promise}
|
|
1277
1304
|
*/
|
|
1278
|
-
async createIndex
|
|
1305
|
+
async createIndex(index) {
|
|
1279
1306
|
this._assertValidIndexAndCollection(index);
|
|
1280
1307
|
|
|
1281
1308
|
let body;
|
|
1282
1309
|
|
|
1283
1310
|
try {
|
|
1284
|
-
({ body } = await this._client.cat.aliases({ format:
|
|
1285
|
-
}
|
|
1286
|
-
catch (error) {
|
|
1311
|
+
({ body } = await this._client.cat.aliases({ format: "json" })); // NOSONAR
|
|
1312
|
+
} catch (error) {
|
|
1287
1313
|
throw this._esWrapper.formatESError(error);
|
|
1288
1314
|
}
|
|
1289
1315
|
|
|
@@ -1292,11 +1318,12 @@ class ElasticSearch extends Service {
|
|
|
1292
1318
|
const indexName = this._extractIndex(alias);
|
|
1293
1319
|
|
|
1294
1320
|
if (index === indexName) {
|
|
1295
|
-
const indexType =
|
|
1296
|
-
|
|
1297
|
-
|
|
1321
|
+
const indexType =
|
|
1322
|
+
alias[INDEX_PREFIX_POSITION_IN_ALIAS] === PRIVATE_PREFIX
|
|
1323
|
+
? "private"
|
|
1324
|
+
: "public";
|
|
1298
1325
|
|
|
1299
|
-
throw kerror.get(
|
|
1326
|
+
throw kerror.get("index_already_exists", indexType, index);
|
|
1300
1327
|
}
|
|
1301
1328
|
}
|
|
1302
1329
|
|
|
@@ -1315,11 +1342,15 @@ class ElasticSearch extends Service {
|
|
|
1315
1342
|
*
|
|
1316
1343
|
* @returns {Promise}
|
|
1317
1344
|
*/
|
|
1318
|
-
async createCollection
|
|
1345
|
+
async createCollection(
|
|
1346
|
+
index,
|
|
1347
|
+
collection,
|
|
1348
|
+
{ mappings = {}, settings = {} } = {}
|
|
1349
|
+
) {
|
|
1319
1350
|
this._assertValidIndexAndCollection(index, collection);
|
|
1320
1351
|
|
|
1321
1352
|
if (collection === HIDDEN_COLLECTION) {
|
|
1322
|
-
throw kerror.get(
|
|
1353
|
+
throw kerror.get("collection_reserved", HIDDEN_COLLECTION);
|
|
1323
1354
|
}
|
|
1324
1355
|
|
|
1325
1356
|
const mutex = new Mutex(`hiddenCollection/create/${index}`);
|
|
@@ -1329,21 +1360,19 @@ class ElasticSearch extends Service {
|
|
|
1329
1360
|
if (await this._hasHiddenCollection(index)) {
|
|
1330
1361
|
await this.deleteCollection(index, HIDDEN_COLLECTION);
|
|
1331
1362
|
}
|
|
1332
|
-
}
|
|
1333
|
-
catch (error) {
|
|
1363
|
+
} catch (error) {
|
|
1334
1364
|
throw this._esWrapper.formatESError(error);
|
|
1335
|
-
}
|
|
1336
|
-
finally {
|
|
1365
|
+
} finally {
|
|
1337
1366
|
await mutex.unlock();
|
|
1338
1367
|
}
|
|
1339
1368
|
|
|
1340
1369
|
const esRequest = {
|
|
1341
1370
|
body: {
|
|
1342
1371
|
aliases: {
|
|
1343
|
-
[this._getAlias(index, collection)]: {}
|
|
1372
|
+
[this._getAlias(index, collection)]: {},
|
|
1344
1373
|
},
|
|
1345
1374
|
mappings: {},
|
|
1346
|
-
settings
|
|
1375
|
+
settings,
|
|
1347
1376
|
},
|
|
1348
1377
|
index: await this._getAvailableIndice(index, collection),
|
|
1349
1378
|
};
|
|
@@ -1362,14 +1391,17 @@ class ElasticSearch extends Service {
|
|
|
1362
1391
|
dynamic: mappings.dynamic || this._config.commonMapping.dynamic,
|
|
1363
1392
|
properties: _.merge(
|
|
1364
1393
|
mappings.properties,
|
|
1365
|
-
this._config.commonMapping.properties
|
|
1394
|
+
this._config.commonMapping.properties
|
|
1395
|
+
),
|
|
1366
1396
|
};
|
|
1367
1397
|
|
|
1368
1398
|
try {
|
|
1369
1399
|
await this._client.indices.create(esRequest);
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1400
|
+
} catch (error) {
|
|
1401
|
+
if (
|
|
1402
|
+
_.get(error, "meta.body.error.type") ===
|
|
1403
|
+
"resource_already_exists_exception"
|
|
1404
|
+
) {
|
|
1373
1405
|
// race condition: the indice has been created between the "exists"
|
|
1374
1406
|
// check above and this "create" attempt
|
|
1375
1407
|
return null;
|
|
@@ -1381,6 +1413,31 @@ class ElasticSearch extends Service {
|
|
|
1381
1413
|
return null;
|
|
1382
1414
|
}
|
|
1383
1415
|
|
|
1416
|
+
/**
|
|
1417
|
+
* Retrieves settings definition for index/type
|
|
1418
|
+
*
|
|
1419
|
+
* @param {String} index - Index name
|
|
1420
|
+
* @param {String} collection - Collection name
|
|
1421
|
+
*
|
|
1422
|
+
* @returns {Promise.<{ settings }>}
|
|
1423
|
+
*/
|
|
1424
|
+
async getSettings(index, collection) {
|
|
1425
|
+
const indice = await this._getIndice(index, collection);
|
|
1426
|
+
const esRequest = {
|
|
1427
|
+
index: indice,
|
|
1428
|
+
};
|
|
1429
|
+
|
|
1430
|
+
debug("Get settings: %o", esRequest);
|
|
1431
|
+
|
|
1432
|
+
try {
|
|
1433
|
+
const { body } = await this._client.indices.getSettings(esRequest);
|
|
1434
|
+
|
|
1435
|
+
return body[indice].settings.index;
|
|
1436
|
+
} catch (error) {
|
|
1437
|
+
throw this._esWrapper.formatESError(error);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1384
1441
|
/**
|
|
1385
1442
|
* Retrieves mapping definition for index/type
|
|
1386
1443
|
*
|
|
@@ -1390,29 +1447,27 @@ class ElasticSearch extends Service {
|
|
|
1390
1447
|
*
|
|
1391
1448
|
* @returns {Promise.<{ dynamic, _meta, properties }>}
|
|
1392
1449
|
*/
|
|
1393
|
-
async getMapping
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
};
|
|
1450
|
+
async getMapping(index, collection, { includeKuzzleMeta = false } = {}) {
|
|
1451
|
+
const indice = await this._getIndice(index, collection);
|
|
1452
|
+
const esRequest = {
|
|
1453
|
+
index: indice,
|
|
1454
|
+
};
|
|
1399
1455
|
|
|
1400
|
-
debug(
|
|
1456
|
+
debug("Get mapping: %o", esRequest);
|
|
1401
1457
|
|
|
1402
1458
|
try {
|
|
1403
1459
|
const { body } = await this._client.indices.getMapping(esRequest);
|
|
1404
1460
|
|
|
1405
1461
|
const properties = includeKuzzleMeta
|
|
1406
1462
|
? body[indice].mappings.properties
|
|
1407
|
-
: _.omit(body[indice].mappings.properties,
|
|
1463
|
+
: _.omit(body[indice].mappings.properties, "_kuzzle_info");
|
|
1408
1464
|
|
|
1409
1465
|
return {
|
|
1410
1466
|
_meta: body[indice].mappings._meta,
|
|
1411
1467
|
dynamic: body[indice].mappings.dynamic,
|
|
1412
|
-
properties
|
|
1468
|
+
properties,
|
|
1413
1469
|
};
|
|
1414
|
-
}
|
|
1415
|
-
catch (error) {
|
|
1470
|
+
} catch (error) {
|
|
1416
1471
|
throw this._esWrapper.formatESError(error);
|
|
1417
1472
|
}
|
|
1418
1473
|
}
|
|
@@ -1426,9 +1481,13 @@ class ElasticSearch extends Service {
|
|
|
1426
1481
|
*
|
|
1427
1482
|
* @returns {Promise}
|
|
1428
1483
|
*/
|
|
1429
|
-
async updateCollection
|
|
1484
|
+
async updateCollection(
|
|
1485
|
+
index,
|
|
1486
|
+
collection,
|
|
1487
|
+
{ mappings = {}, settings = {} } = {}
|
|
1488
|
+
) {
|
|
1430
1489
|
const esRequest = {
|
|
1431
|
-
index: await this._getIndice(index, collection)
|
|
1490
|
+
index: await this._getIndice(index, collection),
|
|
1432
1491
|
};
|
|
1433
1492
|
|
|
1434
1493
|
// If either the putMappings or the putSettings operation fail, we need to
|
|
@@ -1438,17 +1497,16 @@ class ElasticSearch extends Service {
|
|
|
1438
1497
|
let indexSettings;
|
|
1439
1498
|
try {
|
|
1440
1499
|
indexSettings = await this._getSettings(esRequest);
|
|
1441
|
-
}
|
|
1442
|
-
catch (error) {
|
|
1500
|
+
} catch (error) {
|
|
1443
1501
|
throw this._esWrapper.formatESError(error);
|
|
1444
1502
|
}
|
|
1445
1503
|
|
|
1446
|
-
if (!
|
|
1504
|
+
if (!_.isEmpty(settings)) {
|
|
1447
1505
|
await this.updateSettings(index, collection, settings);
|
|
1448
1506
|
}
|
|
1449
1507
|
|
|
1450
1508
|
try {
|
|
1451
|
-
if (!
|
|
1509
|
+
if (!_.isEmpty(mappings)) {
|
|
1452
1510
|
const previousMappings = await this.getMapping(index, collection);
|
|
1453
1511
|
|
|
1454
1512
|
await this.updateMapping(index, collection, mappings);
|
|
@@ -1457,12 +1515,11 @@ class ElasticSearch extends Service {
|
|
|
1457
1515
|
await this.updateSearchIndex(index, collection);
|
|
1458
1516
|
}
|
|
1459
1517
|
}
|
|
1460
|
-
}
|
|
1461
|
-
catch (error) {
|
|
1518
|
+
} catch (error) {
|
|
1462
1519
|
const allowedSettings = this.getAllowedIndexSettings(indexSettings);
|
|
1463
1520
|
|
|
1464
1521
|
// Rollback to previous settings
|
|
1465
|
-
if (!
|
|
1522
|
+
if (!_.isEmpty(settings)) {
|
|
1466
1523
|
await this.updateSettings(index, collection, allowedSettings);
|
|
1467
1524
|
}
|
|
1468
1525
|
|
|
@@ -1478,26 +1535,29 @@ class ElasticSearch extends Service {
|
|
|
1478
1535
|
* @param indexSettings the index settings
|
|
1479
1536
|
* @returns {{index: *}} a new index settings with only allowed settings.
|
|
1480
1537
|
*/
|
|
1481
|
-
getAllowedIndexSettings
|
|
1538
|
+
getAllowedIndexSettings(indexSettings) {
|
|
1482
1539
|
return {
|
|
1483
|
-
index: _.omit(
|
|
1484
|
-
|
|
1485
|
-
|
|
1540
|
+
index: _.omit(indexSettings.index, [
|
|
1541
|
+
"creation_date",
|
|
1542
|
+
"provided_name",
|
|
1543
|
+
"uuid",
|
|
1544
|
+
"version",
|
|
1545
|
+
]),
|
|
1486
1546
|
};
|
|
1487
1547
|
}
|
|
1488
1548
|
|
|
1489
1549
|
/**
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
async updateSearchIndex
|
|
1550
|
+
* Sends an empty UpdateByQuery request to update the search index
|
|
1551
|
+
*
|
|
1552
|
+
* @param {String} index - Index name
|
|
1553
|
+
* @param {String} collection - Collection name
|
|
1554
|
+
* @returns {Promise.<Object>} {}
|
|
1555
|
+
*/
|
|
1556
|
+
async updateSearchIndex(index, collection) {
|
|
1497
1557
|
const esRequest = {
|
|
1498
1558
|
body: {},
|
|
1499
1559
|
// @cluster: conflicts when two nodes start at the same time
|
|
1500
|
-
conflicts:
|
|
1560
|
+
conflicts: "proceed",
|
|
1501
1561
|
index: this._getAlias(index, collection),
|
|
1502
1562
|
refresh: true,
|
|
1503
1563
|
// This operation can take some time: this should be an ES
|
|
@@ -1506,12 +1566,11 @@ class ElasticSearch extends Service {
|
|
|
1506
1566
|
waitForCompletion: false,
|
|
1507
1567
|
};
|
|
1508
1568
|
|
|
1509
|
-
debug(
|
|
1569
|
+
debug("UpdateByQuery: %o", esRequest);
|
|
1510
1570
|
|
|
1511
1571
|
try {
|
|
1512
1572
|
await this._client.updateByQuery(esRequest);
|
|
1513
|
-
}
|
|
1514
|
-
catch (error) {
|
|
1573
|
+
} catch (error) {
|
|
1515
1574
|
throw this._esWrapper.formatESError(error);
|
|
1516
1575
|
}
|
|
1517
1576
|
}
|
|
@@ -1525,9 +1584,9 @@ class ElasticSearch extends Service {
|
|
|
1525
1584
|
*
|
|
1526
1585
|
* @returns {Promise.<{ dynamic, _meta, properties }>}
|
|
1527
1586
|
*/
|
|
1528
|
-
async updateMapping
|
|
1587
|
+
async updateMapping(index, collection, mappings = {}) {
|
|
1529
1588
|
const esRequest = {
|
|
1530
|
-
index: this._getAlias(index, collection)
|
|
1589
|
+
index: this._getAlias(index, collection),
|
|
1531
1590
|
};
|
|
1532
1591
|
|
|
1533
1592
|
this._checkDynamicProperty(mappings);
|
|
@@ -1539,26 +1598,26 @@ class ElasticSearch extends Service {
|
|
|
1539
1598
|
esRequest.body = {
|
|
1540
1599
|
_meta: mappings._meta || collectionMappings._meta,
|
|
1541
1600
|
dynamic: mappings.dynamic || collectionMappings.dynamic,
|
|
1542
|
-
properties: mappings.properties
|
|
1601
|
+
properties: mappings.properties,
|
|
1543
1602
|
};
|
|
1544
1603
|
|
|
1545
|
-
debug(
|
|
1604
|
+
debug("Update mapping: %o", esRequest);
|
|
1546
1605
|
|
|
1547
1606
|
try {
|
|
1548
1607
|
await this._client.indices.putMapping(esRequest);
|
|
1549
|
-
}
|
|
1550
|
-
catch (error) {
|
|
1608
|
+
} catch (error) {
|
|
1551
1609
|
throw this._esWrapper.formatESError(error);
|
|
1552
1610
|
}
|
|
1553
1611
|
|
|
1554
1612
|
const fullProperties = _.merge(
|
|
1555
1613
|
collectionMappings.properties,
|
|
1556
|
-
mappings.properties
|
|
1614
|
+
mappings.properties
|
|
1615
|
+
);
|
|
1557
1616
|
|
|
1558
1617
|
return {
|
|
1559
1618
|
_meta: esRequest.body._meta,
|
|
1560
1619
|
dynamic: esRequest.body.dynamic,
|
|
1561
|
-
properties: fullProperties
|
|
1620
|
+
properties: fullProperties,
|
|
1562
1621
|
};
|
|
1563
1622
|
}
|
|
1564
1623
|
|
|
@@ -1571,20 +1630,18 @@ class ElasticSearch extends Service {
|
|
|
1571
1630
|
*
|
|
1572
1631
|
* @returns {Promise}
|
|
1573
1632
|
*/
|
|
1574
|
-
async updateSettings
|
|
1633
|
+
async updateSettings(index, collection, settings = {}) {
|
|
1575
1634
|
const esRequest = {
|
|
1576
|
-
index: this._getAlias(index, collection)
|
|
1635
|
+
index: this._getAlias(index, collection),
|
|
1577
1636
|
};
|
|
1578
1637
|
|
|
1579
1638
|
await this._client.indices.close(esRequest);
|
|
1580
1639
|
|
|
1581
1640
|
try {
|
|
1582
1641
|
await this._client.indices.putSettings({ ...esRequest, body: settings });
|
|
1583
|
-
}
|
|
1584
|
-
catch (error) {
|
|
1642
|
+
} catch (error) {
|
|
1585
1643
|
throw this._esWrapper.formatESError(error);
|
|
1586
|
-
}
|
|
1587
|
-
finally {
|
|
1644
|
+
} finally {
|
|
1588
1645
|
await this._client.indices.open(esRequest);
|
|
1589
1646
|
}
|
|
1590
1647
|
|
|
@@ -1599,20 +1656,22 @@ class ElasticSearch extends Service {
|
|
|
1599
1656
|
*
|
|
1600
1657
|
* @returns {Promise}
|
|
1601
1658
|
*/
|
|
1602
|
-
async truncateCollection
|
|
1659
|
+
async truncateCollection(index, collection) {
|
|
1603
1660
|
let mappings;
|
|
1604
1661
|
let settings;
|
|
1605
1662
|
|
|
1606
1663
|
const esRequest = {
|
|
1607
|
-
index: await this._getIndice(index, collection)
|
|
1664
|
+
index: await this._getIndice(index, collection),
|
|
1608
1665
|
};
|
|
1609
1666
|
|
|
1610
1667
|
try {
|
|
1611
|
-
mappings = await this.getMapping(index, collection, {
|
|
1668
|
+
mappings = await this.getMapping(index, collection, {
|
|
1669
|
+
includeKuzzleMeta: true,
|
|
1670
|
+
});
|
|
1612
1671
|
settings = await this._getSettings(esRequest);
|
|
1613
1672
|
settings = {
|
|
1614
1673
|
...settings,
|
|
1615
|
-
...this.getAllowedIndexSettings(settings)
|
|
1674
|
+
...this.getAllowedIndexSettings(settings),
|
|
1616
1675
|
};
|
|
1617
1676
|
await this._client.indices.delete(esRequest);
|
|
1618
1677
|
|
|
@@ -1620,16 +1679,15 @@ class ElasticSearch extends Service {
|
|
|
1620
1679
|
...esRequest,
|
|
1621
1680
|
body: {
|
|
1622
1681
|
aliases: {
|
|
1623
|
-
[this._getAlias(index, collection)]: {}
|
|
1682
|
+
[this._getAlias(index, collection)]: {},
|
|
1624
1683
|
},
|
|
1625
1684
|
mappings,
|
|
1626
|
-
settings
|
|
1627
|
-
}
|
|
1685
|
+
settings,
|
|
1686
|
+
},
|
|
1628
1687
|
});
|
|
1629
1688
|
|
|
1630
1689
|
return null;
|
|
1631
|
-
}
|
|
1632
|
-
catch (error) {
|
|
1690
|
+
} catch (error) {
|
|
1633
1691
|
throw this._esWrapper.formatESError(error);
|
|
1634
1692
|
}
|
|
1635
1693
|
}
|
|
@@ -1644,31 +1702,31 @@ class ElasticSearch extends Service {
|
|
|
1644
1702
|
*
|
|
1645
1703
|
* @returns {Promise.<{ items, errors }>
|
|
1646
1704
|
*/
|
|
1647
|
-
async import
|
|
1705
|
+
async import(
|
|
1648
1706
|
index,
|
|
1649
1707
|
collection,
|
|
1650
1708
|
documents,
|
|
1651
|
-
{ refresh, timeout, userId = null } = {}
|
|
1709
|
+
{ refresh, timeout, userId = null } = {}
|
|
1652
1710
|
) {
|
|
1653
1711
|
const alias = this._getAlias(index, collection);
|
|
1654
|
-
const actionNames = [
|
|
1712
|
+
const actionNames = ["index", "create", "update", "delete"];
|
|
1655
1713
|
const dateNow = Date.now();
|
|
1656
1714
|
const esRequest = {
|
|
1657
1715
|
body: documents,
|
|
1658
1716
|
refresh,
|
|
1659
|
-
timeout
|
|
1717
|
+
timeout,
|
|
1660
1718
|
};
|
|
1661
1719
|
const kuzzleMeta = {
|
|
1662
1720
|
created: {
|
|
1663
1721
|
author: getKuid(userId),
|
|
1664
1722
|
createdAt: dateNow,
|
|
1665
1723
|
updatedAt: null,
|
|
1666
|
-
updater: null
|
|
1724
|
+
updater: null,
|
|
1667
1725
|
},
|
|
1668
1726
|
updated: {
|
|
1669
1727
|
updatedAt: dateNow,
|
|
1670
|
-
updater: getKuid(userId)
|
|
1671
|
-
}
|
|
1728
|
+
updater: getKuid(userId),
|
|
1729
|
+
},
|
|
1672
1730
|
};
|
|
1673
1731
|
|
|
1674
1732
|
assertWellFormedRefresh(esRequest);
|
|
@@ -1693,13 +1751,11 @@ class ElasticSearch extends Service {
|
|
|
1693
1751
|
if (item[action]._type) {
|
|
1694
1752
|
item[action]._type = undefined;
|
|
1695
1753
|
}
|
|
1696
|
-
}
|
|
1697
|
-
else if (lastAction === 'index' || lastAction === 'create') {
|
|
1754
|
+
} else if (lastAction === "index" || lastAction === "create") {
|
|
1698
1755
|
item._kuzzle_info = kuzzleMeta.created;
|
|
1699
|
-
}
|
|
1700
|
-
else if (lastAction === 'update') {
|
|
1756
|
+
} else if (lastAction === "update") {
|
|
1701
1757
|
// we can only update metadata on a partial update, or on an upsert
|
|
1702
|
-
for (const prop of [
|
|
1758
|
+
for (const prop of ["doc", "upsert"]) {
|
|
1703
1759
|
if (isPlainObject(item[prop])) {
|
|
1704
1760
|
item[prop]._kuzzle_info = kuzzleMeta.updated;
|
|
1705
1761
|
}
|
|
@@ -1711,8 +1767,7 @@ class ElasticSearch extends Service {
|
|
|
1711
1767
|
let response;
|
|
1712
1768
|
try {
|
|
1713
1769
|
response = await this._client.bulk(esRequest);
|
|
1714
|
-
}
|
|
1715
|
-
catch (error) {
|
|
1770
|
+
} catch (error) {
|
|
1716
1771
|
throw this._esWrapper.formatESError(error);
|
|
1717
1772
|
}
|
|
1718
1773
|
|
|
@@ -1720,7 +1775,7 @@ class ElasticSearch extends Service {
|
|
|
1720
1775
|
|
|
1721
1776
|
const result = {
|
|
1722
1777
|
errors: [],
|
|
1723
|
-
items: []
|
|
1778
|
+
items: [],
|
|
1724
1779
|
};
|
|
1725
1780
|
|
|
1726
1781
|
let idx = 0;
|
|
@@ -1738,16 +1793,15 @@ class ElasticSearch extends Service {
|
|
|
1738
1793
|
if (item.status >= 400) {
|
|
1739
1794
|
const error = {
|
|
1740
1795
|
_id: item._id,
|
|
1741
|
-
status: item.status
|
|
1796
|
+
status: item.status,
|
|
1742
1797
|
};
|
|
1743
1798
|
|
|
1744
1799
|
// update action contain body in "doc" field
|
|
1745
1800
|
// the delete action is not followed by an action payload
|
|
1746
|
-
if (action ===
|
|
1801
|
+
if (action === "update") {
|
|
1747
1802
|
error._source = documents[idx + 1].doc;
|
|
1748
1803
|
error._source._kuzzle_info = undefined;
|
|
1749
|
-
}
|
|
1750
|
-
else if (action !== 'delete') {
|
|
1804
|
+
} else if (action !== "delete") {
|
|
1751
1805
|
error._source = documents[idx + 1];
|
|
1752
1806
|
error._source._kuzzle_info = undefined;
|
|
1753
1807
|
}
|
|
@@ -1757,25 +1811,22 @@ class ElasticSearch extends Service {
|
|
|
1757
1811
|
if (item.error) {
|
|
1758
1812
|
error.error = {
|
|
1759
1813
|
reason: item.error.reason,
|
|
1760
|
-
type: item.error.type
|
|
1814
|
+
type: item.error.type,
|
|
1761
1815
|
};
|
|
1762
1816
|
}
|
|
1763
1817
|
|
|
1764
1818
|
result.errors.push({ [action]: error });
|
|
1765
|
-
}
|
|
1766
|
-
else {
|
|
1819
|
+
} else {
|
|
1767
1820
|
result.items.push({
|
|
1768
1821
|
[action]: {
|
|
1769
1822
|
_id: item._id,
|
|
1770
|
-
status: item.status
|
|
1771
|
-
}
|
|
1823
|
+
status: item.status,
|
|
1824
|
+
},
|
|
1772
1825
|
});
|
|
1773
1826
|
}
|
|
1774
1827
|
|
|
1775
1828
|
// the delete action is not followed by an action payload
|
|
1776
|
-
idx = action ===
|
|
1777
|
-
? idx + 1
|
|
1778
|
-
: idx + 2;
|
|
1829
|
+
idx = action === "delete" ? idx + 1 : idx + 2;
|
|
1779
1830
|
}
|
|
1780
1831
|
/* end critical code section */
|
|
1781
1832
|
|
|
@@ -1790,13 +1841,12 @@ class ElasticSearch extends Service {
|
|
|
1790
1841
|
*
|
|
1791
1842
|
* @returns {Promise.<Array>} Collection names
|
|
1792
1843
|
*/
|
|
1793
|
-
async listCollections
|
|
1844
|
+
async listCollections(index, { includeHidden = false } = {}) {
|
|
1794
1845
|
let body;
|
|
1795
1846
|
|
|
1796
1847
|
try {
|
|
1797
|
-
({ body } = await this._client.cat.aliases({ format:
|
|
1798
|
-
}
|
|
1799
|
-
catch (error) {
|
|
1848
|
+
({ body } = await this._client.cat.aliases({ format: "json" }));
|
|
1849
|
+
} catch (error) {
|
|
1800
1850
|
throw this._esWrapper.formatESError(error);
|
|
1801
1851
|
}
|
|
1802
1852
|
|
|
@@ -1812,13 +1862,12 @@ class ElasticSearch extends Service {
|
|
|
1812
1862
|
*
|
|
1813
1863
|
* @returns {Promise.<Array>} Index names
|
|
1814
1864
|
*/
|
|
1815
|
-
async listIndexes
|
|
1865
|
+
async listIndexes() {
|
|
1816
1866
|
let body;
|
|
1817
1867
|
|
|
1818
1868
|
try {
|
|
1819
|
-
({ body } = await this._client.cat.aliases({ format:
|
|
1820
|
-
}
|
|
1821
|
-
catch (error) {
|
|
1869
|
+
({ body } = await this._client.cat.aliases({ format: "json" }));
|
|
1870
|
+
} catch (error) {
|
|
1822
1871
|
throw this._esWrapper.formatESError(error);
|
|
1823
1872
|
}
|
|
1824
1873
|
|
|
@@ -1834,16 +1883,15 @@ class ElasticSearch extends Service {
|
|
|
1834
1883
|
*
|
|
1835
1884
|
* @returns {Object.<String, String[]>} Object<index, collections>
|
|
1836
1885
|
*/
|
|
1837
|
-
async getSchema
|
|
1886
|
+
async getSchema() {
|
|
1838
1887
|
// This check avoids a breaking change for those who were using Kuzzle before
|
|
1839
1888
|
// alias attribution for each indice was the standard ('auto-version')
|
|
1840
1889
|
await this._ensureAliasConsistency();
|
|
1841
1890
|
|
|
1842
1891
|
let body;
|
|
1843
1892
|
try {
|
|
1844
|
-
({ body } = await this._client.cat.aliases({ format:
|
|
1845
|
-
}
|
|
1846
|
-
catch (error) {
|
|
1893
|
+
({ body } = await this._client.cat.aliases({ format: "json" }));
|
|
1894
|
+
} catch (error) {
|
|
1847
1895
|
throw this._esWrapper.formatESError(error);
|
|
1848
1896
|
}
|
|
1849
1897
|
|
|
@@ -1852,7 +1900,7 @@ class ElasticSearch extends Service {
|
|
|
1852
1900
|
const schema = this._extractSchema(aliases, { includeHidden: true });
|
|
1853
1901
|
|
|
1854
1902
|
for (const [index, collections] of Object.entries(schema)) {
|
|
1855
|
-
schema[index] = collections.filter(c => c !== HIDDEN_COLLECTION);
|
|
1903
|
+
schema[index] = collections.filter((c) => c !== HIDDEN_COLLECTION);
|
|
1856
1904
|
}
|
|
1857
1905
|
|
|
1858
1906
|
return schema;
|
|
@@ -1863,13 +1911,12 @@ class ElasticSearch extends Service {
|
|
|
1863
1911
|
*
|
|
1864
1912
|
* @returns {Promise.<Object[]>} [ { alias, index, collection, indice } ]
|
|
1865
1913
|
*/
|
|
1866
|
-
async listAliases
|
|
1914
|
+
async listAliases() {
|
|
1867
1915
|
let body;
|
|
1868
1916
|
|
|
1869
1917
|
try {
|
|
1870
|
-
({ body } = await this._client.cat.aliases({ format:
|
|
1871
|
-
}
|
|
1872
|
-
catch (error) {
|
|
1918
|
+
({ body } = await this._client.cat.aliases({ format: "json" }));
|
|
1919
|
+
} catch (error) {
|
|
1873
1920
|
throw this._esWrapper.formatESError(error);
|
|
1874
1921
|
}
|
|
1875
1922
|
|
|
@@ -1896,17 +1943,16 @@ class ElasticSearch extends Service {
|
|
|
1896
1943
|
*
|
|
1897
1944
|
* @returns {Promise}
|
|
1898
1945
|
*/
|
|
1899
|
-
async deleteCollection
|
|
1946
|
+
async deleteCollection(index, collection) {
|
|
1900
1947
|
const esRequest = {
|
|
1901
|
-
index: await this._getIndice(index, collection)
|
|
1948
|
+
index: await this._getIndice(index, collection),
|
|
1902
1949
|
};
|
|
1903
1950
|
|
|
1904
1951
|
try {
|
|
1905
1952
|
await this._client.indices.delete(esRequest);
|
|
1906
1953
|
|
|
1907
1954
|
await this._createHiddenCollection(index);
|
|
1908
|
-
}
|
|
1909
|
-
catch (e) {
|
|
1955
|
+
} catch (e) {
|
|
1910
1956
|
throw this._esWrapper.formatESError(e);
|
|
1911
1957
|
}
|
|
1912
1958
|
|
|
@@ -1920,33 +1966,38 @@ class ElasticSearch extends Service {
|
|
|
1920
1966
|
*
|
|
1921
1967
|
* @returns {Promise.<String[]>}
|
|
1922
1968
|
*/
|
|
1923
|
-
async deleteIndexes
|
|
1969
|
+
async deleteIndexes(indexes = []) {
|
|
1924
1970
|
if (indexes.length === 0) {
|
|
1925
1971
|
return Bluebird.resolve([]);
|
|
1926
1972
|
}
|
|
1927
1973
|
const deleted = new Set();
|
|
1928
1974
|
|
|
1929
1975
|
try {
|
|
1930
|
-
const { body } = await this._client.cat.aliases({ format:
|
|
1976
|
+
const { body } = await this._client.cat.aliases({ format: "json" });
|
|
1931
1977
|
|
|
1932
|
-
const esRequest = body.reduce(
|
|
1933
|
-
|
|
1978
|
+
const esRequest = body.reduce(
|
|
1979
|
+
(request, { alias, index: indice }) => {
|
|
1980
|
+
const index = this._extractIndex(alias);
|
|
1934
1981
|
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1982
|
+
if (
|
|
1983
|
+
alias[INDEX_PREFIX_POSITION_IN_ALIAS] !== this._indexPrefix ||
|
|
1984
|
+
!indexes.includes(index)
|
|
1985
|
+
) {
|
|
1986
|
+
return request;
|
|
1987
|
+
}
|
|
1938
1988
|
|
|
1939
|
-
|
|
1940
|
-
|
|
1989
|
+
deleted.add(index);
|
|
1990
|
+
request.index.push(indice);
|
|
1941
1991
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1992
|
+
return request;
|
|
1993
|
+
},
|
|
1994
|
+
{ index: [] }
|
|
1995
|
+
);
|
|
1944
1996
|
|
|
1945
|
-
debug(
|
|
1997
|
+
debug("Delete indexes: %o", esRequest);
|
|
1946
1998
|
|
|
1947
1999
|
await this._client.indices.delete(esRequest);
|
|
1948
|
-
}
|
|
1949
|
-
catch (error) {
|
|
2000
|
+
} catch (error) {
|
|
1950
2001
|
throw this._esWrapper.formatESError(error);
|
|
1951
2002
|
}
|
|
1952
2003
|
|
|
@@ -1960,7 +2011,7 @@ class ElasticSearch extends Service {
|
|
|
1960
2011
|
*
|
|
1961
2012
|
* @returns {Promise}
|
|
1962
2013
|
*/
|
|
1963
|
-
async deleteIndex
|
|
2014
|
+
async deleteIndex(index) {
|
|
1964
2015
|
await this.deleteIndexes([index]);
|
|
1965
2016
|
return null;
|
|
1966
2017
|
}
|
|
@@ -1976,7 +2027,7 @@ class ElasticSearch extends Service {
|
|
|
1976
2027
|
*
|
|
1977
2028
|
* @returns {Promise.<Object>} { _shards }
|
|
1978
2029
|
*/
|
|
1979
|
-
async refreshCollection
|
|
2030
|
+
async refreshCollection(index, collection) {
|
|
1980
2031
|
const esRequest = {
|
|
1981
2032
|
index: this._getAlias(index, collection),
|
|
1982
2033
|
};
|
|
@@ -1984,9 +2035,10 @@ class ElasticSearch extends Service {
|
|
|
1984
2035
|
let _shards;
|
|
1985
2036
|
|
|
1986
2037
|
try {
|
|
1987
|
-
({
|
|
1988
|
-
|
|
1989
|
-
|
|
2038
|
+
({
|
|
2039
|
+
body: { _shards },
|
|
2040
|
+
} = await this._client.indices.refresh(esRequest));
|
|
2041
|
+
} catch (error) {
|
|
1990
2042
|
throw this._esWrapper.formatESError(error);
|
|
1991
2043
|
}
|
|
1992
2044
|
|
|
@@ -2002,18 +2054,17 @@ class ElasticSearch extends Service {
|
|
|
2002
2054
|
*
|
|
2003
2055
|
* @returns {Promise.<boolean>}
|
|
2004
2056
|
*/
|
|
2005
|
-
async exists
|
|
2057
|
+
async exists(index, collection, id) {
|
|
2006
2058
|
const esRequest = {
|
|
2007
2059
|
id,
|
|
2008
|
-
index: this._getAlias(index, collection)
|
|
2060
|
+
index: this._getAlias(index, collection),
|
|
2009
2061
|
};
|
|
2010
2062
|
|
|
2011
2063
|
try {
|
|
2012
2064
|
const { body: exists } = await this._client.exists(esRequest);
|
|
2013
2065
|
|
|
2014
2066
|
return exists;
|
|
2015
|
-
}
|
|
2016
|
-
catch (error) {
|
|
2067
|
+
} catch (error) {
|
|
2017
2068
|
throw this._esWrapper.formatESError(error);
|
|
2018
2069
|
}
|
|
2019
2070
|
}
|
|
@@ -2029,7 +2080,7 @@ class ElasticSearch extends Service {
|
|
|
2029
2080
|
*
|
|
2030
2081
|
* @returns {Promise.<{ items: Array<{ _id, _source, _version }>, errors }>}
|
|
2031
2082
|
*/
|
|
2032
|
-
async mExists
|
|
2083
|
+
async mExists(index, collection, ids) {
|
|
2033
2084
|
if (ids.length === 0) {
|
|
2034
2085
|
return { errors: [], item: [] };
|
|
2035
2086
|
}
|
|
@@ -2037,19 +2088,18 @@ class ElasticSearch extends Service {
|
|
|
2037
2088
|
const esRequest = {
|
|
2038
2089
|
_source: false,
|
|
2039
2090
|
body: {
|
|
2040
|
-
docs: ids.map(_id => ({ _id })),
|
|
2091
|
+
docs: ids.map((_id) => ({ _id })),
|
|
2041
2092
|
},
|
|
2042
|
-
index: this._getAlias(index, collection)
|
|
2093
|
+
index: this._getAlias(index, collection),
|
|
2043
2094
|
};
|
|
2044
2095
|
|
|
2045
|
-
debug(
|
|
2096
|
+
debug("mExists: %o", esRequest);
|
|
2046
2097
|
|
|
2047
2098
|
let body;
|
|
2048
2099
|
|
|
2049
2100
|
try {
|
|
2050
2101
|
({ body } = await this._client.mget(esRequest)); // NOSONAR
|
|
2051
|
-
}
|
|
2052
|
-
catch (e) {
|
|
2102
|
+
} catch (e) {
|
|
2053
2103
|
throw this._esWrapper.formatESError(e);
|
|
2054
2104
|
}
|
|
2055
2105
|
|
|
@@ -2060,11 +2110,8 @@ class ElasticSearch extends Service {
|
|
|
2060
2110
|
const doc = body.docs[i];
|
|
2061
2111
|
|
|
2062
2112
|
if (doc.found) {
|
|
2063
|
-
items.push(
|
|
2064
|
-
|
|
2065
|
-
);
|
|
2066
|
-
}
|
|
2067
|
-
else {
|
|
2113
|
+
items.push(doc._id);
|
|
2114
|
+
} else {
|
|
2068
2115
|
errors.push(doc._id);
|
|
2069
2116
|
}
|
|
2070
2117
|
}
|
|
@@ -2079,10 +2126,10 @@ class ElasticSearch extends Service {
|
|
|
2079
2126
|
*
|
|
2080
2127
|
* @returns {Promise.<boolean>}
|
|
2081
2128
|
*/
|
|
2082
|
-
async hasIndex
|
|
2129
|
+
async hasIndex(index) {
|
|
2083
2130
|
const indexes = await this.listIndexes();
|
|
2084
2131
|
|
|
2085
|
-
return indexes.some(idx => idx === index);
|
|
2132
|
+
return indexes.some((idx) => idx === index);
|
|
2086
2133
|
}
|
|
2087
2134
|
|
|
2088
2135
|
/**
|
|
@@ -2093,10 +2140,10 @@ class ElasticSearch extends Service {
|
|
|
2093
2140
|
*
|
|
2094
2141
|
* @returns {Promise.<boolean>}
|
|
2095
2142
|
*/
|
|
2096
|
-
async hasCollection
|
|
2143
|
+
async hasCollection(index, collection) {
|
|
2097
2144
|
const collections = await this.listCollections(index);
|
|
2098
2145
|
|
|
2099
|
-
return collections.some(col => col === collection);
|
|
2146
|
+
return collections.some((col) => col === collection);
|
|
2100
2147
|
}
|
|
2101
2148
|
|
|
2102
2149
|
/**
|
|
@@ -2106,10 +2153,12 @@ class ElasticSearch extends Service {
|
|
|
2106
2153
|
*
|
|
2107
2154
|
* @returns {Promise.<boolean>}
|
|
2108
2155
|
*/
|
|
2109
|
-
async _hasHiddenCollection
|
|
2110
|
-
const collections = await this.listCollections(index, {
|
|
2156
|
+
async _hasHiddenCollection(index) {
|
|
2157
|
+
const collections = await this.listCollections(index, {
|
|
2158
|
+
includeHidden: true,
|
|
2159
|
+
});
|
|
2111
2160
|
|
|
2112
|
-
return collections.some(col => col === HIDDEN_COLLECTION);
|
|
2161
|
+
return collections.some((col) => col === HIDDEN_COLLECTION);
|
|
2113
2162
|
}
|
|
2114
2163
|
|
|
2115
2164
|
/**
|
|
@@ -2124,41 +2173,41 @@ class ElasticSearch extends Service {
|
|
|
2124
2173
|
*
|
|
2125
2174
|
* @returns {Promise.<Object>} { items, errors }
|
|
2126
2175
|
*/
|
|
2127
|
-
async mCreate
|
|
2176
|
+
async mCreate(
|
|
2128
2177
|
index,
|
|
2129
2178
|
collection,
|
|
2130
2179
|
documents,
|
|
2131
|
-
{ refresh, timeout, userId = null } = {}
|
|
2132
|
-
|
|
2133
|
-
|
|
2180
|
+
{ refresh, timeout, userId = null } = {}
|
|
2181
|
+
) {
|
|
2182
|
+
const alias = this._getAlias(index, collection),
|
|
2134
2183
|
kuzzleMeta = {
|
|
2135
2184
|
_kuzzle_info: {
|
|
2136
2185
|
author: getKuid(userId),
|
|
2137
2186
|
createdAt: Date.now(),
|
|
2138
2187
|
updatedAt: null,
|
|
2139
|
-
updater: null
|
|
2140
|
-
}
|
|
2188
|
+
updater: null,
|
|
2189
|
+
},
|
|
2141
2190
|
},
|
|
2142
|
-
{
|
|
2143
|
-
|
|
2144
|
-
extractedDocuments,
|
|
2145
|
-
documentsToGet
|
|
2146
|
-
} = this._extractMDocuments(documents, kuzzleMeta, { prepareMGet: true });
|
|
2191
|
+
{ rejected, extractedDocuments, documentsToGet } =
|
|
2192
|
+
this._extractMDocuments(documents, kuzzleMeta, { prepareMGet: true });
|
|
2147
2193
|
|
|
2148
2194
|
// prepare the mget request, but only for document having a specified id
|
|
2149
|
-
const { body } =
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2195
|
+
const { body } =
|
|
2196
|
+
documentsToGet.length > 0
|
|
2197
|
+
? await this._client.mget({
|
|
2198
|
+
body: { docs: documentsToGet },
|
|
2199
|
+
index: alias,
|
|
2200
|
+
})
|
|
2201
|
+
: { body: { docs: [] } };
|
|
2202
|
+
|
|
2203
|
+
const existingDocuments = body.docs;
|
|
2204
|
+
const esRequest = {
|
|
2205
|
+
body: [],
|
|
2206
|
+
index: alias,
|
|
2207
|
+
refresh,
|
|
2208
|
+
timeout,
|
|
2209
|
+
};
|
|
2210
|
+
const toImport = [];
|
|
2162
2211
|
|
|
2163
2212
|
/**
|
|
2164
2213
|
* @warning Critical code section
|
|
@@ -2169,34 +2218,32 @@ class ElasticSearch extends Service {
|
|
|
2169
2218
|
const document = extractedDocuments[i];
|
|
2170
2219
|
|
|
2171
2220
|
// Documents are retrieved in the same order than we got them from user
|
|
2172
|
-
if (typeof document._id ===
|
|
2221
|
+
if (typeof document._id === "string" && existingDocuments[idx]) {
|
|
2173
2222
|
if (existingDocuments[idx].found) {
|
|
2174
2223
|
document._source._kuzzle_info = undefined;
|
|
2175
2224
|
|
|
2176
2225
|
rejected.push({
|
|
2177
2226
|
document: {
|
|
2178
2227
|
_id: document._id,
|
|
2179
|
-
body: document._source
|
|
2228
|
+
body: document._source,
|
|
2180
2229
|
},
|
|
2181
|
-
reason:
|
|
2182
|
-
status: 400
|
|
2230
|
+
reason: "document already exists",
|
|
2231
|
+
status: 400,
|
|
2183
2232
|
});
|
|
2184
2233
|
|
|
2185
2234
|
idx++;
|
|
2186
|
-
}
|
|
2187
|
-
else {
|
|
2235
|
+
} else {
|
|
2188
2236
|
esRequest.body.push({
|
|
2189
2237
|
index: {
|
|
2190
2238
|
_id: document._id,
|
|
2191
|
-
_index: alias
|
|
2192
|
-
}
|
|
2239
|
+
_index: alias,
|
|
2240
|
+
},
|
|
2193
2241
|
});
|
|
2194
2242
|
esRequest.body.push(document._source);
|
|
2195
2243
|
|
|
2196
2244
|
toImport.push(document);
|
|
2197
2245
|
}
|
|
2198
|
-
}
|
|
2199
|
-
else {
|
|
2246
|
+
} else {
|
|
2200
2247
|
esRequest.body.push({ index: { _index: alias } });
|
|
2201
2248
|
esRequest.body.push(document._source);
|
|
2202
2249
|
|
|
@@ -2218,11 +2265,19 @@ class ElasticSearch extends Service {
|
|
|
2218
2265
|
*
|
|
2219
2266
|
* @returns {Promise.<{ items, errors }>
|
|
2220
2267
|
*/
|
|
2221
|
-
async mCreateOrReplace
|
|
2268
|
+
async mCreateOrReplace(
|
|
2222
2269
|
index,
|
|
2223
2270
|
collection,
|
|
2224
2271
|
documents,
|
|
2225
|
-
{
|
|
2272
|
+
{
|
|
2273
|
+
refresh,
|
|
2274
|
+
timeout,
|
|
2275
|
+
userId = null,
|
|
2276
|
+
injectKuzzleMeta = true,
|
|
2277
|
+
limits = true,
|
|
2278
|
+
source = true,
|
|
2279
|
+
} = {}
|
|
2280
|
+
) {
|
|
2226
2281
|
let kuzzleMeta = {};
|
|
2227
2282
|
|
|
2228
2283
|
if (injectKuzzleMeta) {
|
|
@@ -2231,8 +2286,8 @@ class ElasticSearch extends Service {
|
|
|
2231
2286
|
author: getKuid(userId),
|
|
2232
2287
|
createdAt: Date.now(),
|
|
2233
2288
|
updatedAt: null,
|
|
2234
|
-
updater: null
|
|
2235
|
-
}
|
|
2289
|
+
updater: null,
|
|
2290
|
+
},
|
|
2236
2291
|
};
|
|
2237
2292
|
}
|
|
2238
2293
|
|
|
@@ -2241,12 +2296,12 @@ class ElasticSearch extends Service {
|
|
|
2241
2296
|
body: [],
|
|
2242
2297
|
index: alias,
|
|
2243
2298
|
refresh,
|
|
2244
|
-
timeout
|
|
2299
|
+
timeout,
|
|
2245
2300
|
};
|
|
2246
|
-
const {
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2301
|
+
const { rejected, extractedDocuments } = this._extractMDocuments(
|
|
2302
|
+
documents,
|
|
2303
|
+
kuzzleMeta
|
|
2304
|
+
);
|
|
2250
2305
|
|
|
2251
2306
|
esRequest.body = [];
|
|
2252
2307
|
|
|
@@ -2259,14 +2314,17 @@ class ElasticSearch extends Service {
|
|
|
2259
2314
|
esRequest.body.push({
|
|
2260
2315
|
index: {
|
|
2261
2316
|
_id: extractedDocuments[i]._id,
|
|
2262
|
-
_index: alias
|
|
2263
|
-
}
|
|
2317
|
+
_index: alias,
|
|
2318
|
+
},
|
|
2264
2319
|
});
|
|
2265
2320
|
esRequest.body.push(extractedDocuments[i]._source);
|
|
2266
2321
|
}
|
|
2267
2322
|
/* end critical code section */
|
|
2268
2323
|
|
|
2269
|
-
return this._mExecute(esRequest, extractedDocuments, rejected, {
|
|
2324
|
+
return this._mExecute(esRequest, extractedDocuments, rejected, {
|
|
2325
|
+
limits,
|
|
2326
|
+
source,
|
|
2327
|
+
});
|
|
2270
2328
|
}
|
|
2271
2329
|
|
|
2272
2330
|
/**
|
|
@@ -2281,30 +2339,30 @@ class ElasticSearch extends Service {
|
|
|
2281
2339
|
*
|
|
2282
2340
|
* @returns {Promise.<Object>} { items, errors }
|
|
2283
2341
|
*/
|
|
2284
|
-
async mUpdate
|
|
2342
|
+
async mUpdate(
|
|
2285
2343
|
index,
|
|
2286
2344
|
collection,
|
|
2287
2345
|
documents,
|
|
2288
|
-
{ refresh, retryOnConflict = 0, timeout, userId = null } = {}
|
|
2289
|
-
|
|
2290
|
-
|
|
2346
|
+
{ refresh, retryOnConflict = 0, timeout, userId = null } = {}
|
|
2347
|
+
) {
|
|
2348
|
+
const alias = this._getAlias(index, collection),
|
|
2291
2349
|
toImport = [],
|
|
2292
2350
|
esRequest = {
|
|
2293
2351
|
body: [],
|
|
2294
2352
|
index: alias,
|
|
2295
2353
|
refresh,
|
|
2296
|
-
timeout
|
|
2354
|
+
timeout,
|
|
2297
2355
|
},
|
|
2298
2356
|
kuzzleMeta = {
|
|
2299
2357
|
_kuzzle_info: {
|
|
2300
2358
|
updatedAt: Date.now(),
|
|
2301
|
-
updater: getKuid(userId)
|
|
2302
|
-
}
|
|
2359
|
+
updater: getKuid(userId),
|
|
2360
|
+
},
|
|
2303
2361
|
},
|
|
2304
|
-
{
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2362
|
+
{ rejected, extractedDocuments } = this._extractMDocuments(
|
|
2363
|
+
documents,
|
|
2364
|
+
kuzzleMeta
|
|
2365
|
+
);
|
|
2308
2366
|
|
|
2309
2367
|
/**
|
|
2310
2368
|
* @warning Critical code section
|
|
@@ -2314,33 +2372,33 @@ class ElasticSearch extends Service {
|
|
|
2314
2372
|
for (let i = 0; i < extractedDocuments.length; i++) {
|
|
2315
2373
|
const extractedDocument = extractedDocuments[i];
|
|
2316
2374
|
|
|
2317
|
-
if (typeof extractedDocument._id ===
|
|
2375
|
+
if (typeof extractedDocument._id === "string") {
|
|
2318
2376
|
esRequest.body.push({
|
|
2319
2377
|
update: {
|
|
2320
2378
|
_id: extractedDocument._id,
|
|
2321
2379
|
_index: alias,
|
|
2322
|
-
retry_on_conflict:
|
|
2323
|
-
|
|
2380
|
+
retry_on_conflict:
|
|
2381
|
+
retryOnConflict || this._config.defaults.onUpdateConflictRetries,
|
|
2382
|
+
},
|
|
2324
2383
|
});
|
|
2325
2384
|
|
|
2326
2385
|
// _source: true => makes ES return the updated document source in the
|
|
2327
2386
|
// response. Required by the real-time notifier component
|
|
2328
2387
|
esRequest.body.push({
|
|
2329
2388
|
_source: true,
|
|
2330
|
-
doc: extractedDocument._source
|
|
2389
|
+
doc: extractedDocument._source,
|
|
2331
2390
|
});
|
|
2332
2391
|
toImport.push(extractedDocument);
|
|
2333
|
-
}
|
|
2334
|
-
else {
|
|
2392
|
+
} else {
|
|
2335
2393
|
extractedDocument._source._kuzzle_info = undefined;
|
|
2336
2394
|
|
|
2337
2395
|
rejected.push({
|
|
2338
2396
|
document: {
|
|
2339
2397
|
_id: extractedDocument._id,
|
|
2340
|
-
body: extractedDocument._source
|
|
2398
|
+
body: extractedDocument._source,
|
|
2341
2399
|
},
|
|
2342
|
-
reason:
|
|
2343
|
-
status: 400
|
|
2400
|
+
reason: "document _id must be a string",
|
|
2401
|
+
status: 400,
|
|
2344
2402
|
});
|
|
2345
2403
|
}
|
|
2346
2404
|
}
|
|
@@ -2352,11 +2410,11 @@ class ElasticSearch extends Service {
|
|
|
2352
2410
|
// response.result.get._source
|
|
2353
2411
|
// => we replace response.result._source with it so that the notifier
|
|
2354
2412
|
// module can seamlessly process all kind of m* response*
|
|
2355
|
-
response.items = response.items.map(item => ({
|
|
2413
|
+
response.items = response.items.map((item) => ({
|
|
2356
2414
|
_id: item._id,
|
|
2357
2415
|
_source: item.get._source,
|
|
2358
2416
|
_version: item._version,
|
|
2359
|
-
status: item.status
|
|
2417
|
+
status: item.status,
|
|
2360
2418
|
}));
|
|
2361
2419
|
|
|
2362
2420
|
return response;
|
|
@@ -2372,16 +2430,17 @@ class ElasticSearch extends Service {
|
|
|
2372
2430
|
*
|
|
2373
2431
|
* @returns {Promise.<{ items, errors }>
|
|
2374
2432
|
*/
|
|
2375
|
-
async mUpsert
|
|
2433
|
+
async mUpsert(
|
|
2376
2434
|
index,
|
|
2377
2435
|
collection,
|
|
2378
2436
|
documents,
|
|
2379
|
-
{ refresh, retryOnConflict = 0, timeout, userId = null } = {}
|
|
2437
|
+
{ refresh, retryOnConflict = 0, timeout, userId = null } = {}
|
|
2438
|
+
) {
|
|
2380
2439
|
const alias = this._getAlias(index, collection);
|
|
2381
2440
|
const esRequest = {
|
|
2382
2441
|
body: [],
|
|
2383
2442
|
refresh,
|
|
2384
|
-
timeout
|
|
2443
|
+
timeout,
|
|
2385
2444
|
};
|
|
2386
2445
|
|
|
2387
2446
|
const user = getKuid(userId);
|
|
@@ -2390,15 +2449,15 @@ class ElasticSearch extends Service {
|
|
|
2390
2449
|
doc: {
|
|
2391
2450
|
_kuzzle_info: {
|
|
2392
2451
|
updatedAt: now,
|
|
2393
|
-
updater: user
|
|
2394
|
-
}
|
|
2452
|
+
updater: user,
|
|
2453
|
+
},
|
|
2395
2454
|
},
|
|
2396
2455
|
upsert: {
|
|
2397
2456
|
_kuzzle_info: {
|
|
2398
2457
|
author: user,
|
|
2399
|
-
createdAt: now
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2458
|
+
createdAt: now,
|
|
2459
|
+
},
|
|
2460
|
+
},
|
|
2402
2461
|
};
|
|
2403
2462
|
|
|
2404
2463
|
const { rejected, extractedDocuments } = this._extractMDocuments(
|
|
@@ -2406,7 +2465,7 @@ class ElasticSearch extends Service {
|
|
|
2406
2465
|
kuzzleMeta,
|
|
2407
2466
|
{
|
|
2408
2467
|
prepareMUpsert: true,
|
|
2409
|
-
requireId: true
|
|
2468
|
+
requireId: true,
|
|
2410
2469
|
}
|
|
2411
2470
|
);
|
|
2412
2471
|
|
|
@@ -2422,12 +2481,13 @@ class ElasticSearch extends Service {
|
|
|
2422
2481
|
_id: extractedDocuments[i]._id,
|
|
2423
2482
|
_index: alias,
|
|
2424
2483
|
_source: true,
|
|
2425
|
-
retry_on_conflict:
|
|
2426
|
-
|
|
2484
|
+
retry_on_conflict:
|
|
2485
|
+
retryOnConflict || this._config.defaults.onUpdateConflictRetries,
|
|
2486
|
+
},
|
|
2427
2487
|
},
|
|
2428
2488
|
{
|
|
2429
2489
|
doc: extractedDocuments[i]._source.changes,
|
|
2430
|
-
upsert: extractedDocuments[i]._source.default
|
|
2490
|
+
upsert: extractedDocuments[i]._source.default,
|
|
2431
2491
|
}
|
|
2432
2492
|
);
|
|
2433
2493
|
// _source: true
|
|
@@ -2436,18 +2496,22 @@ class ElasticSearch extends Service {
|
|
|
2436
2496
|
}
|
|
2437
2497
|
/* end critical code section */
|
|
2438
2498
|
|
|
2439
|
-
const response = await this._mExecute(
|
|
2499
|
+
const response = await this._mExecute(
|
|
2500
|
+
esRequest,
|
|
2501
|
+
extractedDocuments,
|
|
2502
|
+
rejected
|
|
2503
|
+
);
|
|
2440
2504
|
|
|
2441
2505
|
// with _source: true, ES returns the updated document in
|
|
2442
2506
|
// response.result.get._source
|
|
2443
2507
|
// => we replace response.result._source with it so that the notifier
|
|
2444
2508
|
// module can seamlessly process all kind of m* response*
|
|
2445
|
-
response.items = response.items.map(item => ({
|
|
2509
|
+
response.items = response.items.map((item) => ({
|
|
2446
2510
|
_id: item._id,
|
|
2447
2511
|
_source: item.get._source,
|
|
2448
2512
|
_version: item._version,
|
|
2449
|
-
created: item.result ===
|
|
2450
|
-
status: item.status
|
|
2513
|
+
created: item.result === "created", // Needed by the notifier
|
|
2514
|
+
status: item.status,
|
|
2451
2515
|
}));
|
|
2452
2516
|
|
|
2453
2517
|
return response;
|
|
@@ -2465,29 +2529,26 @@ class ElasticSearch extends Service {
|
|
|
2465
2529
|
*
|
|
2466
2530
|
* @returns {Promise.<Object>} { items, errors }
|
|
2467
2531
|
*/
|
|
2468
|
-
async mReplace
|
|
2532
|
+
async mReplace(
|
|
2469
2533
|
index,
|
|
2470
2534
|
collection,
|
|
2471
2535
|
documents,
|
|
2472
|
-
{ refresh, timeout, userId = null } = {}
|
|
2473
|
-
|
|
2474
|
-
|
|
2536
|
+
{ refresh, timeout, userId = null } = {}
|
|
2537
|
+
) {
|
|
2538
|
+
const alias = this._getAlias(index, collection),
|
|
2475
2539
|
kuzzleMeta = {
|
|
2476
2540
|
_kuzzle_info: {
|
|
2477
2541
|
author: getKuid(userId),
|
|
2478
2542
|
createdAt: Date.now(),
|
|
2479
2543
|
updatedAt: null,
|
|
2480
|
-
updater: null
|
|
2481
|
-
}
|
|
2544
|
+
updater: null,
|
|
2545
|
+
},
|
|
2482
2546
|
},
|
|
2483
|
-
{
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
documents,
|
|
2489
|
-
kuzzleMeta,
|
|
2490
|
-
{ prepareMGet: true, requireId: true });
|
|
2547
|
+
{ rejected, extractedDocuments, documentsToGet } =
|
|
2548
|
+
this._extractMDocuments(documents, kuzzleMeta, {
|
|
2549
|
+
prepareMGet: true,
|
|
2550
|
+
requireId: true,
|
|
2551
|
+
});
|
|
2491
2552
|
|
|
2492
2553
|
if (documentsToGet.length < 1) {
|
|
2493
2554
|
return { errors: rejected, items: [] };
|
|
@@ -2495,17 +2556,16 @@ class ElasticSearch extends Service {
|
|
|
2495
2556
|
|
|
2496
2557
|
const { body } = await this._client.mget({
|
|
2497
2558
|
body: { docs: documentsToGet },
|
|
2498
|
-
index: alias
|
|
2559
|
+
index: alias,
|
|
2499
2560
|
});
|
|
2500
2561
|
|
|
2501
|
-
const
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
toImport = [];
|
|
2562
|
+
const existingDocuments = body.docs;
|
|
2563
|
+
const esRequest = {
|
|
2564
|
+
body: [],
|
|
2565
|
+
refresh,
|
|
2566
|
+
timeout,
|
|
2567
|
+
};
|
|
2568
|
+
const toImport = [];
|
|
2509
2569
|
|
|
2510
2570
|
/**
|
|
2511
2571
|
* @warning Critical code section
|
|
@@ -2520,23 +2580,22 @@ class ElasticSearch extends Service {
|
|
|
2520
2580
|
esRequest.body.push({
|
|
2521
2581
|
index: {
|
|
2522
2582
|
_id: document._id,
|
|
2523
|
-
_index: alias
|
|
2524
|
-
}
|
|
2583
|
+
_index: alias,
|
|
2584
|
+
},
|
|
2525
2585
|
});
|
|
2526
2586
|
esRequest.body.push(document._source);
|
|
2527
2587
|
|
|
2528
2588
|
toImport.push(document);
|
|
2529
|
-
}
|
|
2530
|
-
else {
|
|
2589
|
+
} else {
|
|
2531
2590
|
document._source._kuzzle_info = undefined;
|
|
2532
2591
|
|
|
2533
2592
|
rejected.push({
|
|
2534
2593
|
document: {
|
|
2535
2594
|
_id: document._id,
|
|
2536
|
-
body: document._source
|
|
2595
|
+
body: document._source,
|
|
2537
2596
|
},
|
|
2538
|
-
reason:
|
|
2539
|
-
status: 404
|
|
2597
|
+
reason: "document not found",
|
|
2598
|
+
status: 404,
|
|
2540
2599
|
});
|
|
2541
2600
|
}
|
|
2542
2601
|
}
|
|
@@ -2555,15 +2614,10 @@ class ElasticSearch extends Service {
|
|
|
2555
2614
|
*
|
|
2556
2615
|
* @returns {Promise.<{ documents, errors }>
|
|
2557
2616
|
*/
|
|
2558
|
-
async mDelete
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
{ refresh, timeout } = {}) {
|
|
2563
|
-
const
|
|
2564
|
-
query = { ids: { values: [] } },
|
|
2565
|
-
validIds = [],
|
|
2566
|
-
partialErrors = [];
|
|
2617
|
+
async mDelete(index, collection, ids, { refresh, timeout } = {}) {
|
|
2618
|
+
const query = { ids: { values: [] } };
|
|
2619
|
+
const validIds = [];
|
|
2620
|
+
const partialErrors = [];
|
|
2567
2621
|
|
|
2568
2622
|
/**
|
|
2569
2623
|
* @warning Critical code section
|
|
@@ -2573,14 +2627,13 @@ class ElasticSearch extends Service {
|
|
|
2573
2627
|
for (let i = 0; i < ids.length; i++) {
|
|
2574
2628
|
const _id = ids[i];
|
|
2575
2629
|
|
|
2576
|
-
if (typeof _id ===
|
|
2630
|
+
if (typeof _id === "string") {
|
|
2577
2631
|
validIds.push(_id);
|
|
2578
|
-
}
|
|
2579
|
-
else {
|
|
2632
|
+
} else {
|
|
2580
2633
|
partialErrors.push({
|
|
2581
2634
|
_id,
|
|
2582
|
-
reason:
|
|
2583
|
-
status: 400
|
|
2635
|
+
reason: "document _id must be a string",
|
|
2636
|
+
status: 400,
|
|
2584
2637
|
});
|
|
2585
2638
|
}
|
|
2586
2639
|
}
|
|
@@ -2597,19 +2650,17 @@ class ElasticSearch extends Service {
|
|
|
2597
2650
|
* request can contain more than 10K elements
|
|
2598
2651
|
*/
|
|
2599
2652
|
for (let i = 0; i < validIds.length; i++) {
|
|
2600
|
-
const
|
|
2601
|
-
|
|
2602
|
-
item = items[idx];
|
|
2653
|
+
const validId = validIds[i];
|
|
2654
|
+
const item = items[idx];
|
|
2603
2655
|
|
|
2604
2656
|
if (item && item._id === validId) {
|
|
2605
2657
|
query.ids.values.push(validId);
|
|
2606
2658
|
idx++;
|
|
2607
|
-
}
|
|
2608
|
-
else {
|
|
2659
|
+
} else {
|
|
2609
2660
|
partialErrors.push({
|
|
2610
2661
|
_id: validId,
|
|
2611
|
-
reason:
|
|
2612
|
-
status: 404
|
|
2662
|
+
reason: "document not found",
|
|
2663
|
+
status: 404,
|
|
2613
2664
|
});
|
|
2614
2665
|
}
|
|
2615
2666
|
}
|
|
@@ -2617,11 +2668,10 @@ class ElasticSearch extends Service {
|
|
|
2617
2668
|
|
|
2618
2669
|
// @todo duplicated query to get documents body, mGet here and search in
|
|
2619
2670
|
// deleteByQuery
|
|
2620
|
-
const { documents } = await this.deleteByQuery(
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
{ refresh, timeout });
|
|
2671
|
+
const { documents } = await this.deleteByQuery(index, collection, query, {
|
|
2672
|
+
refresh,
|
|
2673
|
+
timeout,
|
|
2674
|
+
});
|
|
2625
2675
|
|
|
2626
2676
|
return { documents, errors: partialErrors };
|
|
2627
2677
|
}
|
|
@@ -2638,13 +2688,19 @@ class ElasticSearch extends Service {
|
|
|
2638
2688
|
*
|
|
2639
2689
|
* @returns {Promise.<Object[]>} results
|
|
2640
2690
|
*/
|
|
2641
|
-
async _mExecute
|
|
2691
|
+
async _mExecute(
|
|
2692
|
+
esRequest,
|
|
2693
|
+
documents,
|
|
2694
|
+
partialErrors,
|
|
2695
|
+
{ limits = true, source = true } = {}
|
|
2696
|
+
) {
|
|
2642
2697
|
assertWellFormedRefresh(esRequest);
|
|
2643
2698
|
|
|
2644
|
-
if (
|
|
2645
|
-
&&
|
|
2699
|
+
if (
|
|
2700
|
+
limits &&
|
|
2701
|
+
documents.length > global.kuzzle.config.limits.documentsWriteCount
|
|
2646
2702
|
) {
|
|
2647
|
-
return kerror.reject(
|
|
2703
|
+
return kerror.reject("write_limit_exceeded");
|
|
2648
2704
|
}
|
|
2649
2705
|
|
|
2650
2706
|
let response = { body: { items: [] } };
|
|
@@ -2652,8 +2708,7 @@ class ElasticSearch extends Service {
|
|
|
2652
2708
|
if (documents.length > 0) {
|
|
2653
2709
|
try {
|
|
2654
2710
|
response = await this._client.bulk(esRequest);
|
|
2655
|
-
}
|
|
2656
|
-
catch (error) {
|
|
2711
|
+
} catch (error) {
|
|
2657
2712
|
throw this._esWrapper.formatESError(error);
|
|
2658
2713
|
}
|
|
2659
2714
|
}
|
|
@@ -2675,26 +2730,24 @@ class ElasticSearch extends Service {
|
|
|
2675
2730
|
partialErrors.push({
|
|
2676
2731
|
document: {
|
|
2677
2732
|
_id: documents[i]._id,
|
|
2678
|
-
body: documents[i]._source
|
|
2733
|
+
body: documents[i]._source,
|
|
2679
2734
|
},
|
|
2680
|
-
reason:
|
|
2681
|
-
status: result.status
|
|
2735
|
+
reason: "document not found",
|
|
2736
|
+
status: result.status,
|
|
2682
2737
|
});
|
|
2683
|
-
}
|
|
2684
|
-
else {
|
|
2738
|
+
} else {
|
|
2685
2739
|
partialErrors.push({
|
|
2686
2740
|
document: documents[i],
|
|
2687
2741
|
reason: result.error.reason,
|
|
2688
|
-
status: result.status
|
|
2742
|
+
status: result.status,
|
|
2689
2743
|
});
|
|
2690
2744
|
}
|
|
2691
|
-
}
|
|
2692
|
-
else {
|
|
2745
|
+
} else {
|
|
2693
2746
|
successes.push({
|
|
2694
2747
|
_id: result._id,
|
|
2695
2748
|
_source: source ? documents[i]._source : undefined,
|
|
2696
2749
|
_version: result._version,
|
|
2697
|
-
created: result.result ===
|
|
2750
|
+
created: result.result === "created",
|
|
2698
2751
|
get: result.get,
|
|
2699
2752
|
result: result.result,
|
|
2700
2753
|
status: result.status, // used by mUpdate to get the full document body
|
|
@@ -2721,11 +2774,14 @@ class ElasticSearch extends Service {
|
|
|
2721
2774
|
*
|
|
2722
2775
|
* @returns {Object} { rejected, extractedDocuments, documentsToGet }
|
|
2723
2776
|
*/
|
|
2724
|
-
_extractMDocuments
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2777
|
+
_extractMDocuments(
|
|
2778
|
+
documents,
|
|
2779
|
+
metadata,
|
|
2780
|
+
{ prepareMGet = false, requireId = false, prepareMUpsert = false } = {}
|
|
2781
|
+
) {
|
|
2782
|
+
const rejected = [];
|
|
2783
|
+
const extractedDocuments = [];
|
|
2784
|
+
const documentsToGet = [];
|
|
2729
2785
|
|
|
2730
2786
|
/**
|
|
2731
2787
|
* @warning Critical code section
|
|
@@ -2735,63 +2791,66 @@ class ElasticSearch extends Service {
|
|
|
2735
2791
|
for (let i = 0; i < documents.length; i++) {
|
|
2736
2792
|
const document = documents[i];
|
|
2737
2793
|
|
|
2738
|
-
if (!
|
|
2794
|
+
if (!isPlainObject(document.body) && !prepareMUpsert) {
|
|
2739
2795
|
rejected.push({
|
|
2740
2796
|
document,
|
|
2741
|
-
reason:
|
|
2742
|
-
status: 400
|
|
2797
|
+
reason: "document body must be an object",
|
|
2798
|
+
status: 400,
|
|
2743
2799
|
});
|
|
2744
|
-
}
|
|
2745
|
-
else if (! isPlainObject(document.changes) && prepareMUpsert) {
|
|
2800
|
+
} else if (!isPlainObject(document.changes) && prepareMUpsert) {
|
|
2746
2801
|
rejected.push({
|
|
2747
2802
|
document,
|
|
2748
|
-
reason:
|
|
2749
|
-
status: 400
|
|
2803
|
+
reason: "document changes must be an object",
|
|
2804
|
+
status: 400,
|
|
2750
2805
|
});
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2806
|
+
} else if (
|
|
2807
|
+
prepareMUpsert &&
|
|
2808
|
+
document.default &&
|
|
2809
|
+
!isPlainObject(document.default)
|
|
2810
|
+
) {
|
|
2753
2811
|
rejected.push({
|
|
2754
2812
|
document,
|
|
2755
|
-
reason:
|
|
2756
|
-
status: 400
|
|
2813
|
+
reason: "document default must be an object",
|
|
2814
|
+
status: 400,
|
|
2757
2815
|
});
|
|
2758
|
-
}
|
|
2759
|
-
else if (requireId && typeof document._id !== 'string') {
|
|
2816
|
+
} else if (requireId && typeof document._id !== "string") {
|
|
2760
2817
|
rejected.push({
|
|
2761
2818
|
document,
|
|
2762
|
-
reason:
|
|
2763
|
-
status: 400
|
|
2819
|
+
reason: "document _id must be a string",
|
|
2820
|
+
status: 400,
|
|
2764
2821
|
});
|
|
2765
|
-
}
|
|
2766
|
-
else {
|
|
2822
|
+
} else {
|
|
2767
2823
|
let extractedDocument;
|
|
2768
2824
|
if (prepareMUpsert) {
|
|
2769
2825
|
extractedDocument = {
|
|
2770
2826
|
_source: {
|
|
2771
2827
|
// Do not use destructuring, it's 10x slower
|
|
2772
2828
|
changes: Object.assign({}, metadata.doc, document.changes),
|
|
2773
|
-
default: Object.assign(
|
|
2774
|
-
|
|
2829
|
+
default: Object.assign(
|
|
2830
|
+
{},
|
|
2831
|
+
metadata.upsert,
|
|
2832
|
+
document.changes,
|
|
2833
|
+
document.default
|
|
2834
|
+
),
|
|
2835
|
+
},
|
|
2775
2836
|
};
|
|
2776
|
-
}
|
|
2777
|
-
else {
|
|
2837
|
+
} else {
|
|
2778
2838
|
extractedDocument = {
|
|
2779
2839
|
// Do not use destructuring, it's 10x slower
|
|
2780
|
-
_source: Object.assign({}, metadata, document.body)
|
|
2840
|
+
_source: Object.assign({}, metadata, document.body),
|
|
2781
2841
|
};
|
|
2782
2842
|
}
|
|
2783
2843
|
|
|
2784
|
-
|
|
2785
2844
|
if (document._id) {
|
|
2786
2845
|
extractedDocument._id = document._id;
|
|
2787
2846
|
}
|
|
2788
2847
|
|
|
2789
2848
|
extractedDocuments.push(extractedDocument);
|
|
2790
2849
|
|
|
2791
|
-
if (prepareMGet && typeof document._id ===
|
|
2850
|
+
if (prepareMGet && typeof document._id === "string") {
|
|
2792
2851
|
documentsToGet.push({
|
|
2793
2852
|
_id: document._id,
|
|
2794
|
-
_source: false
|
|
2853
|
+
_source: false,
|
|
2795
2854
|
});
|
|
2796
2855
|
}
|
|
2797
2856
|
}
|
|
@@ -2807,28 +2866,28 @@ class ElasticSearch extends Service {
|
|
|
2807
2866
|
* @param {Object} mapping
|
|
2808
2867
|
* @throws
|
|
2809
2868
|
*/
|
|
2810
|
-
_checkMappings
|
|
2811
|
-
const
|
|
2812
|
-
|
|
2813
|
-
|
|
2869
|
+
_checkMappings(mapping, path = [], check = true) {
|
|
2870
|
+
const properties = Object.keys(mapping);
|
|
2871
|
+
const mappingProperties =
|
|
2872
|
+
path.length === 0
|
|
2814
2873
|
? ROOT_MAPPING_PROPERTIES
|
|
2815
2874
|
: [...ROOT_MAPPING_PROPERTIES, ...CHILD_MAPPING_PROPERTIES];
|
|
2816
2875
|
|
|
2817
2876
|
for (const property of properties) {
|
|
2818
|
-
if (check && !
|
|
2819
|
-
const currentPath = [...path, property].join(
|
|
2877
|
+
if (check && !mappingProperties.includes(property)) {
|
|
2878
|
+
const currentPath = [...path, property].join(".");
|
|
2820
2879
|
|
|
2821
2880
|
throw kerror.get(
|
|
2822
|
-
|
|
2881
|
+
"invalid_mapping",
|
|
2823
2882
|
currentPath,
|
|
2824
|
-
didYouMean(property, mappingProperties)
|
|
2883
|
+
didYouMean(property, mappingProperties)
|
|
2884
|
+
);
|
|
2825
2885
|
}
|
|
2826
2886
|
|
|
2827
|
-
if (property ===
|
|
2887
|
+
if (property === "properties") {
|
|
2828
2888
|
// type definition level, we don't check
|
|
2829
|
-
this._checkMappings(mapping[property], [...path,
|
|
2830
|
-
}
|
|
2831
|
-
else if (mapping[property] && mapping[property].properties) {
|
|
2889
|
+
this._checkMappings(mapping[property], [...path, "properties"], false);
|
|
2890
|
+
} else if (mapping[property] && mapping[property].properties) {
|
|
2832
2891
|
// root properties level, check for "properties", "dynamic" and "_meta"
|
|
2833
2892
|
this._checkMappings(mapping[property], [...path, property], true);
|
|
2834
2893
|
}
|
|
@@ -2844,7 +2903,7 @@ class ElasticSearch extends Service {
|
|
|
2844
2903
|
*
|
|
2845
2904
|
* @returns {String} Alias name (eg: '@&nepali.liia')
|
|
2846
2905
|
*/
|
|
2847
|
-
_getAlias
|
|
2906
|
+
_getAlias(index, collection) {
|
|
2848
2907
|
return `${ALIAS_PREFIX}${this._indexPrefix}${index}${NAME_SEPARATOR}${collection}`;
|
|
2849
2908
|
}
|
|
2850
2909
|
|
|
@@ -2858,15 +2917,21 @@ class ElasticSearch extends Service {
|
|
|
2858
2917
|
* @returns {String} Indice name (eg: '&nepali.liia')
|
|
2859
2918
|
* @throws If there is not exactly one indice associated
|
|
2860
2919
|
*/
|
|
2861
|
-
async _getIndice
|
|
2920
|
+
async _getIndice(index, collection) {
|
|
2862
2921
|
const alias = `${ALIAS_PREFIX}${this._indexPrefix}${index}${NAME_SEPARATOR}${collection}`;
|
|
2863
|
-
const { body } = await this._client.cat.aliases({
|
|
2922
|
+
const { body } = await this._client.cat.aliases({
|
|
2923
|
+
format: "json",
|
|
2924
|
+
name: alias,
|
|
2925
|
+
});
|
|
2864
2926
|
|
|
2865
2927
|
if (body.length < 1) {
|
|
2866
|
-
throw kerror.get(
|
|
2867
|
-
}
|
|
2868
|
-
|
|
2869
|
-
|
|
2928
|
+
throw kerror.get("unknown_index_collection");
|
|
2929
|
+
} else if (body.length > 1) {
|
|
2930
|
+
throw kerror.get(
|
|
2931
|
+
"multiple_indice_alias",
|
|
2932
|
+
`"alias" starting with "${ALIAS_PREFIX}"`,
|
|
2933
|
+
'"indices"'
|
|
2934
|
+
);
|
|
2870
2935
|
}
|
|
2871
2936
|
|
|
2872
2937
|
return body[0].index;
|
|
@@ -2879,7 +2944,7 @@ class ElasticSearch extends Service {
|
|
|
2879
2944
|
* @return {Promise<*>} the settings of the indice.
|
|
2880
2945
|
* @private
|
|
2881
2946
|
*/
|
|
2882
|
-
async _getSettings
|
|
2947
|
+
async _getSettings(esRequest) {
|
|
2883
2948
|
const response = await this._client.indices.getSettings(esRequest);
|
|
2884
2949
|
return response.body[esRequest.index].settings;
|
|
2885
2950
|
}
|
|
@@ -2893,10 +2958,12 @@ class ElasticSearch extends Service {
|
|
|
2893
2958
|
*
|
|
2894
2959
|
* @returns {String} Available indice name (eg: '&nepali.liia2')
|
|
2895
2960
|
*/
|
|
2896
|
-
async _getAvailableIndice
|
|
2897
|
-
let indice = this._getAlias(index, collection).substr(
|
|
2961
|
+
async _getAvailableIndice(index, collection) {
|
|
2962
|
+
let indice = this._getAlias(index, collection).substr(
|
|
2963
|
+
INDEX_PREFIX_POSITION_IN_ALIAS
|
|
2964
|
+
);
|
|
2898
2965
|
|
|
2899
|
-
if (!
|
|
2966
|
+
if (!(await this._client.indices.exists({ index: indice })).body) {
|
|
2900
2967
|
return indice;
|
|
2901
2968
|
}
|
|
2902
2969
|
|
|
@@ -2906,14 +2973,17 @@ class ElasticSearch extends Service {
|
|
|
2906
2973
|
suffix = `.${randomNumber(100000)}`;
|
|
2907
2974
|
|
|
2908
2975
|
const overflow = Buffer.from(indice + suffix).length - 255;
|
|
2909
|
-
if (
|
|
2976
|
+
if (overflow > 0) {
|
|
2910
2977
|
const indiceBuffer = Buffer.from(indice);
|
|
2911
|
-
indice = indiceBuffer
|
|
2978
|
+
indice = indiceBuffer
|
|
2979
|
+
.slice(0, indiceBuffer.length - overflow)
|
|
2980
|
+
.toString();
|
|
2912
2981
|
}
|
|
2913
2982
|
|
|
2914
|
-
notAvailable = await this._client.indices.exists({
|
|
2915
|
-
|
|
2916
|
-
|
|
2983
|
+
notAvailable = await this._client.indices.exists({
|
|
2984
|
+
index: indice + suffix,
|
|
2985
|
+
}).body;
|
|
2986
|
+
} while (notAvailable);
|
|
2917
2987
|
|
|
2918
2988
|
return indice + suffix;
|
|
2919
2989
|
}
|
|
@@ -2926,14 +2996,14 @@ class ElasticSearch extends Service {
|
|
|
2926
2996
|
* @returns {String} Alias name (eg: '@&nepali.liia')
|
|
2927
2997
|
* @throws If there is not exactly one alias associated that is prefixed with @
|
|
2928
2998
|
*/
|
|
2929
|
-
async _getAliasFromIndice
|
|
2999
|
+
async _getAliasFromIndice(indice) {
|
|
2930
3000
|
const { body } = await this._client.indices.getAlias({ index: indice });
|
|
2931
|
-
const aliases =
|
|
2932
|
-
|
|
2933
|
-
|
|
3001
|
+
const aliases = Object.keys(body[indice].aliases).filter((alias) =>
|
|
3002
|
+
alias.startsWith(ALIAS_PREFIX)
|
|
3003
|
+
);
|
|
2934
3004
|
|
|
2935
3005
|
if (aliases.length < 1) {
|
|
2936
|
-
throw kerror.get(
|
|
3006
|
+
throw kerror.get("unknown_index_collection");
|
|
2937
3007
|
}
|
|
2938
3008
|
|
|
2939
3009
|
return aliases;
|
|
@@ -2946,26 +3016,29 @@ class ElasticSearch extends Service {
|
|
|
2946
3016
|
* This check avoids a breaking change for those who were using Kuzzle before
|
|
2947
3017
|
* alias attribution for each indice turned into a standard ('auto-version').
|
|
2948
3018
|
*/
|
|
2949
|
-
async _ensureAliasConsistency
|
|
3019
|
+
async _ensureAliasConsistency() {
|
|
2950
3020
|
try {
|
|
2951
|
-
const { body } = await this._client.cat.indices({ format:
|
|
3021
|
+
const { body } = await this._client.cat.indices({ format: "json" });
|
|
2952
3022
|
const indices = body.map(({ index: indice }) => indice);
|
|
2953
3023
|
const aliases = await this.listAliases();
|
|
2954
3024
|
|
|
2955
|
-
const indicesWithoutAlias = indices.filter(
|
|
2956
|
-
indice
|
|
2957
|
-
|
|
3025
|
+
const indicesWithoutAlias = indices.filter(
|
|
3026
|
+
(indice) =>
|
|
3027
|
+
indice[INDEX_PREFIX_POSITION_IN_INDICE] === this._indexPrefix &&
|
|
3028
|
+
!aliases.some((alias) => alias.indice === indice)
|
|
3029
|
+
);
|
|
2958
3030
|
|
|
2959
3031
|
const esRequest = { body: { actions: [] } };
|
|
2960
3032
|
for (const indice of indicesWithoutAlias) {
|
|
2961
|
-
esRequest.body.actions.push({
|
|
3033
|
+
esRequest.body.actions.push({
|
|
3034
|
+
add: { alias: `${ALIAS_PREFIX}${indice}`, index: indice },
|
|
3035
|
+
});
|
|
2962
3036
|
}
|
|
2963
3037
|
|
|
2964
3038
|
if (esRequest.body.actions.length > 0) {
|
|
2965
3039
|
await this._client.indices.updateAliases(esRequest);
|
|
2966
3040
|
}
|
|
2967
|
-
}
|
|
2968
|
-
catch (error) {
|
|
3041
|
+
} catch (error) {
|
|
2969
3042
|
throw this._esWrapper.formatESError(error);
|
|
2970
3043
|
}
|
|
2971
3044
|
}
|
|
@@ -2976,13 +3049,13 @@ class ElasticSearch extends Service {
|
|
|
2976
3049
|
* @param {String} index
|
|
2977
3050
|
* @param {String} collection
|
|
2978
3051
|
*/
|
|
2979
|
-
_assertValidIndexAndCollection
|
|
2980
|
-
if (!
|
|
2981
|
-
throw kerror.get(
|
|
3052
|
+
_assertValidIndexAndCollection(index, collection = null) {
|
|
3053
|
+
if (!this.isIndexNameValid(index)) {
|
|
3054
|
+
throw kerror.get("invalid_index_name", index);
|
|
2982
3055
|
}
|
|
2983
3056
|
|
|
2984
|
-
if (collection !== null && !
|
|
2985
|
-
throw kerror.get(
|
|
3057
|
+
if (collection !== null && !this.isCollectionNameValid(collection)) {
|
|
3058
|
+
throw kerror.get("invalid_collection_name", collection);
|
|
2986
3059
|
}
|
|
2987
3060
|
}
|
|
2988
3061
|
|
|
@@ -2993,10 +3066,11 @@ class ElasticSearch extends Service {
|
|
|
2993
3066
|
*
|
|
2994
3067
|
* @returns {String} Index name
|
|
2995
3068
|
*/
|
|
2996
|
-
_extractIndex
|
|
3069
|
+
_extractIndex(alias) {
|
|
2997
3070
|
return alias.substr(
|
|
2998
3071
|
INDEX_PREFIX_POSITION_IN_ALIAS + 1,
|
|
2999
|
-
alias.indexOf(NAME_SEPARATOR) - INDEX_PREFIX_POSITION_IN_ALIAS - 1
|
|
3072
|
+
alias.indexOf(NAME_SEPARATOR) - INDEX_PREFIX_POSITION_IN_ALIAS - 1
|
|
3073
|
+
);
|
|
3000
3074
|
}
|
|
3001
3075
|
|
|
3002
3076
|
/**
|
|
@@ -3006,7 +3080,7 @@ class ElasticSearch extends Service {
|
|
|
3006
3080
|
*
|
|
3007
3081
|
* @returns {String} Collection name
|
|
3008
3082
|
*/
|
|
3009
|
-
_extractCollection
|
|
3083
|
+
_extractCollection(alias) {
|
|
3010
3084
|
const separatorPos = alias.indexOf(NAME_SEPARATOR);
|
|
3011
3085
|
|
|
3012
3086
|
return alias.substr(separatorPos + 1, alias.length);
|
|
@@ -3020,22 +3094,23 @@ class ElasticSearch extends Service {
|
|
|
3020
3094
|
*
|
|
3021
3095
|
* @returns {Object.<String, String[]>} Indexes as key and an array of their collections as value
|
|
3022
3096
|
*/
|
|
3023
|
-
_extractSchema
|
|
3097
|
+
_extractSchema(aliases, { includeHidden = false } = {}) {
|
|
3024
3098
|
const schema = {};
|
|
3025
3099
|
|
|
3026
3100
|
for (const alias of aliases) {
|
|
3027
|
-
const [
|
|
3101
|
+
const [indexName, collectionName] = alias
|
|
3028
3102
|
.substr(INDEX_PREFIX_POSITION_IN_ALIAS + 1, alias.length)
|
|
3029
3103
|
.split(NAME_SEPARATOR);
|
|
3030
3104
|
|
|
3031
|
-
if (
|
|
3032
|
-
|
|
3105
|
+
if (
|
|
3106
|
+
alias[INDEX_PREFIX_POSITION_IN_ALIAS] === this._indexPrefix &&
|
|
3107
|
+
(collectionName !== HIDDEN_COLLECTION || includeHidden)
|
|
3033
3108
|
) {
|
|
3034
|
-
if (!
|
|
3109
|
+
if (!schema[indexName]) {
|
|
3035
3110
|
schema[indexName] = [];
|
|
3036
3111
|
}
|
|
3037
3112
|
|
|
3038
|
-
if (!
|
|
3113
|
+
if (!schema[indexName].includes(collectionName)) {
|
|
3039
3114
|
schema[indexName].push(collectionName);
|
|
3040
3115
|
}
|
|
3041
3116
|
}
|
|
@@ -3050,7 +3125,7 @@ class ElasticSearch extends Service {
|
|
|
3050
3125
|
*
|
|
3051
3126
|
* @param {String} index Index name
|
|
3052
3127
|
*/
|
|
3053
|
-
async _createHiddenCollection
|
|
3128
|
+
async _createHiddenCollection(index) {
|
|
3054
3129
|
const mutex = new Mutex(`hiddenCollection/${index}`);
|
|
3055
3130
|
|
|
3056
3131
|
try {
|
|
@@ -3063,20 +3138,18 @@ class ElasticSearch extends Service {
|
|
|
3063
3138
|
await this._client.indices.create({
|
|
3064
3139
|
body: {
|
|
3065
3140
|
aliases: {
|
|
3066
|
-
[this._getAlias(index, HIDDEN_COLLECTION)]: {}
|
|
3141
|
+
[this._getAlias(index, HIDDEN_COLLECTION)]: {},
|
|
3067
3142
|
},
|
|
3068
3143
|
settings: {
|
|
3069
3144
|
number_of_replicas: 1,
|
|
3070
3145
|
number_of_shards: 1,
|
|
3071
|
-
}
|
|
3146
|
+
},
|
|
3072
3147
|
},
|
|
3073
3148
|
index: await this._getAvailableIndice(index, HIDDEN_COLLECTION),
|
|
3074
3149
|
});
|
|
3075
|
-
}
|
|
3076
|
-
catch (e) {
|
|
3150
|
+
} catch (e) {
|
|
3077
3151
|
throw this._esWrapper.formatESError(e);
|
|
3078
|
-
}
|
|
3079
|
-
finally {
|
|
3152
|
+
} finally {
|
|
3080
3153
|
await mutex.unlock();
|
|
3081
3154
|
}
|
|
3082
3155
|
}
|
|
@@ -3090,25 +3163,31 @@ class ElasticSearch extends Service {
|
|
|
3090
3163
|
*
|
|
3091
3164
|
* @returns {Promise.<Array>} resolve to an array of documents
|
|
3092
3165
|
*/
|
|
3093
|
-
async _getAllDocumentsFromQuery
|
|
3094
|
-
let {
|
|
3166
|
+
async _getAllDocumentsFromQuery(esRequest) {
|
|
3167
|
+
let {
|
|
3168
|
+
body: { hits, _scroll_id },
|
|
3169
|
+
} = await this._client.search(esRequest);
|
|
3095
3170
|
|
|
3096
3171
|
if (hits.total.value > global.kuzzle.config.limits.documentsWriteCount) {
|
|
3097
|
-
throw kerror.get(
|
|
3172
|
+
throw kerror.get("write_limit_exceeded");
|
|
3098
3173
|
}
|
|
3099
3174
|
|
|
3100
|
-
let documents = hits.hits.map(h => ({ _id: h._id, _source: h._source }));
|
|
3175
|
+
let documents = hits.hits.map((h) => ({ _id: h._id, _source: h._source }));
|
|
3101
3176
|
|
|
3102
3177
|
while (hits.total.value !== documents.length) {
|
|
3103
|
-
({
|
|
3178
|
+
({
|
|
3179
|
+
body: { hits, _scroll_id },
|
|
3180
|
+
} = await this._client.scroll({
|
|
3104
3181
|
scroll: esRequest.scroll,
|
|
3105
|
-
scrollId: _scroll_id
|
|
3182
|
+
scrollId: _scroll_id,
|
|
3106
3183
|
}));
|
|
3107
3184
|
|
|
3108
|
-
documents = documents.concat(
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3185
|
+
documents = documents.concat(
|
|
3186
|
+
hits.hits.map((h) => ({
|
|
3187
|
+
_id: h._id,
|
|
3188
|
+
_source: h._source,
|
|
3189
|
+
}))
|
|
3190
|
+
);
|
|
3112
3191
|
}
|
|
3113
3192
|
|
|
3114
3193
|
await this.clearScroll(_scroll_id);
|
|
@@ -3122,11 +3201,11 @@ class ElasticSearch extends Service {
|
|
|
3122
3201
|
*
|
|
3123
3202
|
* @param {Object} searchBody - ES search body (with query, aggregations, sort, etc)
|
|
3124
3203
|
*/
|
|
3125
|
-
_sanitizeSearchBody
|
|
3204
|
+
_sanitizeSearchBody(searchBody) {
|
|
3126
3205
|
// Only allow a whitelist of top level properties
|
|
3127
3206
|
for (const key of Object.keys(searchBody)) {
|
|
3128
|
-
if (searchBody[key] !== undefined && !
|
|
3129
|
-
throw kerror.get(
|
|
3207
|
+
if (searchBody[key] !== undefined && !this.searchBodyKeys.includes(key)) {
|
|
3208
|
+
throw kerror.get("invalid_search_query", key);
|
|
3130
3209
|
}
|
|
3131
3210
|
}
|
|
3132
3211
|
|
|
@@ -3149,17 +3228,17 @@ class ElasticSearch extends Service {
|
|
|
3149
3228
|
*
|
|
3150
3229
|
* @param {Object} object
|
|
3151
3230
|
*/
|
|
3152
|
-
_scriptCheck
|
|
3231
|
+
_scriptCheck(object) {
|
|
3153
3232
|
for (const [key, value] of Object.entries(object)) {
|
|
3154
3233
|
if (this.scriptKeys.includes(key)) {
|
|
3155
3234
|
for (const scriptArg of Object.keys(value)) {
|
|
3156
|
-
if (!
|
|
3157
|
-
throw kerror.get(
|
|
3235
|
+
if (!this.scriptAllowedArgs.includes(scriptArg)) {
|
|
3236
|
+
throw kerror.get("invalid_query_keyword", `${key}.${scriptArg}`);
|
|
3158
3237
|
}
|
|
3159
3238
|
}
|
|
3160
3239
|
}
|
|
3161
3240
|
// Every object must be checked here, even the ones nested into an array
|
|
3162
|
-
else if (typeof value ===
|
|
3241
|
+
else if (typeof value === "object" && value !== null) {
|
|
3163
3242
|
this._scriptCheck(value);
|
|
3164
3243
|
}
|
|
3165
3244
|
}
|
|
@@ -3170,7 +3249,7 @@ class ElasticSearch extends Service {
|
|
|
3170
3249
|
* @param {string} name
|
|
3171
3250
|
* @returns {Boolean}
|
|
3172
3251
|
*/
|
|
3173
|
-
isCollectionNameValid
|
|
3252
|
+
isCollectionNameValid(name) {
|
|
3174
3253
|
return _isObjectNameValid(name);
|
|
3175
3254
|
}
|
|
3176
3255
|
|
|
@@ -3179,7 +3258,7 @@ class ElasticSearch extends Service {
|
|
|
3179
3258
|
* @param {string} name
|
|
3180
3259
|
* @returns {Boolean}
|
|
3181
3260
|
*/
|
|
3182
|
-
isIndexNameValid
|
|
3261
|
+
isIndexNameValid(name) {
|
|
3183
3262
|
return _isObjectNameValid(name);
|
|
3184
3263
|
}
|
|
3185
3264
|
|
|
@@ -3188,9 +3267,9 @@ class ElasticSearch extends Service {
|
|
|
3188
3267
|
* @param {[type]} id [description]
|
|
3189
3268
|
* @returns {[type]} [description]
|
|
3190
3269
|
*/
|
|
3191
|
-
async clearScroll
|
|
3270
|
+
async clearScroll(id) {
|
|
3192
3271
|
if (id) {
|
|
3193
|
-
debug(
|
|
3272
|
+
debug("clearing scroll: %s", id);
|
|
3194
3273
|
await this._client.clearScroll({ scrollId: id });
|
|
3195
3274
|
}
|
|
3196
3275
|
}
|
|
@@ -3203,18 +3282,20 @@ class ElasticSearch extends Service {
|
|
|
3203
3282
|
*
|
|
3204
3283
|
* @returns {Number} milliseconds
|
|
3205
3284
|
*/
|
|
3206
|
-
_loadMsConfig
|
|
3285
|
+
_loadMsConfig(key) {
|
|
3207
3286
|
const configValue = _.get(this._config, key);
|
|
3208
3287
|
|
|
3209
3288
|
assert(
|
|
3210
|
-
typeof configValue ===
|
|
3211
|
-
`services.storageEngine.${key} must be a string.`
|
|
3289
|
+
typeof configValue === "string",
|
|
3290
|
+
`services.storageEngine.${key} must be a string.`
|
|
3291
|
+
);
|
|
3212
3292
|
|
|
3213
3293
|
const parsedValue = ms(configValue);
|
|
3214
3294
|
|
|
3215
3295
|
assert(
|
|
3216
|
-
typeof parsedValue ===
|
|
3217
|
-
`Invalid parsed value from ms() for services.storageEngine.${key} ("${typeof parsedValue}").`
|
|
3296
|
+
typeof parsedValue === "number",
|
|
3297
|
+
`Invalid parsed value from ms() for services.storageEngine.${key} ("${typeof parsedValue}").`
|
|
3298
|
+
);
|
|
3218
3299
|
|
|
3219
3300
|
return parsedValue;
|
|
3220
3301
|
}
|
|
@@ -3223,17 +3304,17 @@ class ElasticSearch extends Service {
|
|
|
3223
3304
|
* Returns true if one of the mappings dynamic property changes value from
|
|
3224
3305
|
* false to true
|
|
3225
3306
|
*/
|
|
3226
|
-
_dynamicChanges
|
|
3307
|
+
_dynamicChanges(previousMappings, newMappings) {
|
|
3227
3308
|
const previousValues = findDynamic(previousMappings);
|
|
3228
3309
|
|
|
3229
3310
|
for (const [path, previousValue] of Object.entries(previousValues)) {
|
|
3230
|
-
if (previousValue.toString() !==
|
|
3311
|
+
if (previousValue.toString() !== "false") {
|
|
3231
3312
|
continue;
|
|
3232
3313
|
}
|
|
3233
3314
|
|
|
3234
3315
|
const newValue = _.get(newMappings, path);
|
|
3235
3316
|
|
|
3236
|
-
if (newValue && newValue.toString() !==
|
|
3317
|
+
if (newValue && newValue.toString() !== "false") {
|
|
3237
3318
|
return true;
|
|
3238
3319
|
}
|
|
3239
3320
|
}
|
|
@@ -3241,7 +3322,7 @@ class ElasticSearch extends Service {
|
|
|
3241
3322
|
return false;
|
|
3242
3323
|
}
|
|
3243
3324
|
|
|
3244
|
-
async waitForElasticsearch
|
|
3325
|
+
async waitForElasticsearch() {
|
|
3245
3326
|
if (esState !== esStateEnum.NONE) {
|
|
3246
3327
|
while (esState !== esStateEnum.OK) {
|
|
3247
3328
|
await Bluebird.delay(1000);
|
|
@@ -3252,7 +3333,7 @@ class ElasticSearch extends Service {
|
|
|
3252
3333
|
|
|
3253
3334
|
esState = esStateEnum.AWAITING;
|
|
3254
3335
|
|
|
3255
|
-
global.kuzzle.log.info(
|
|
3336
|
+
global.kuzzle.log.info("[ℹ] Trying to connect to Elasticsearch...");
|
|
3256
3337
|
|
|
3257
3338
|
while (esState !== esStateEnum.OK) {
|
|
3258
3339
|
try {
|
|
@@ -3262,15 +3343,15 @@ class ElasticSearch extends Service {
|
|
|
3262
3343
|
});
|
|
3263
3344
|
|
|
3264
3345
|
if (health.body.number_of_pending_tasks === 0) {
|
|
3265
|
-
global.kuzzle.log.info(
|
|
3346
|
+
global.kuzzle.log.info("[✔] Elasticsearch is ready");
|
|
3266
3347
|
esState = esStateEnum.OK;
|
|
3267
|
-
}
|
|
3268
|
-
|
|
3269
|
-
|
|
3348
|
+
} else {
|
|
3349
|
+
global.kuzzle.log.info(
|
|
3350
|
+
`[ℹ] Still waiting for Elasticsearch: ${health.body.number_of_pending_tasks} cluster tasks remaining`
|
|
3351
|
+
);
|
|
3270
3352
|
await Bluebird.delay(1000);
|
|
3271
3353
|
}
|
|
3272
|
-
}
|
|
3273
|
-
catch (e) {
|
|
3354
|
+
} catch (e) {
|
|
3274
3355
|
await Bluebird.delay(1000);
|
|
3275
3356
|
}
|
|
3276
3357
|
}
|
|
@@ -3279,25 +3360,28 @@ class ElasticSearch extends Service {
|
|
|
3279
3360
|
/**
|
|
3280
3361
|
* Checks if the dynamic properties are correct
|
|
3281
3362
|
*/
|
|
3282
|
-
_checkDynamicProperty
|
|
3363
|
+
_checkDynamicProperty(mappings) {
|
|
3283
3364
|
const dynamicProperties = findDynamic(mappings);
|
|
3284
3365
|
for (const [path, value] of Object.entries(dynamicProperties)) {
|
|
3285
3366
|
// Prevent common mistake
|
|
3286
|
-
if (typeof value ===
|
|
3367
|
+
if (typeof value === "boolean") {
|
|
3287
3368
|
_.set(mappings, path, value.toString());
|
|
3288
|
-
}
|
|
3289
|
-
else if (typeof value !== 'string') {
|
|
3369
|
+
} else if (typeof value !== "string") {
|
|
3290
3370
|
throw kerror.get(
|
|
3291
|
-
|
|
3371
|
+
"invalid_mapping",
|
|
3292
3372
|
path,
|
|
3293
|
-
|
|
3373
|
+
"Dynamic property value should be a string."
|
|
3374
|
+
);
|
|
3294
3375
|
}
|
|
3295
3376
|
|
|
3296
|
-
if (!
|
|
3377
|
+
if (!DYNAMIC_PROPERTY_VALUES.includes(value.toString())) {
|
|
3297
3378
|
throw kerror.get(
|
|
3298
|
-
|
|
3379
|
+
"invalid_mapping",
|
|
3299
3380
|
path,
|
|
3300
|
-
`Incorrect dynamic property value (${value}). Should be one of "${DYNAMIC_PROPERTY_VALUES.join(
|
|
3381
|
+
`Incorrect dynamic property value (${value}). Should be one of "${DYNAMIC_PROPERTY_VALUES.join(
|
|
3382
|
+
'", "'
|
|
3383
|
+
)}"`
|
|
3384
|
+
);
|
|
3301
3385
|
}
|
|
3302
3386
|
}
|
|
3303
3387
|
}
|
|
@@ -3316,9 +3400,9 @@ module.exports = ElasticSearch;
|
|
|
3316
3400
|
* "properties.user.properties.address.dynamic": "strict"
|
|
3317
3401
|
* }
|
|
3318
3402
|
*/
|
|
3319
|
-
function findDynamic
|
|
3403
|
+
function findDynamic(mappings, path = [], results = {}) {
|
|
3320
3404
|
if (mappings.dynamic !== undefined) {
|
|
3321
|
-
results[path.concat(
|
|
3405
|
+
results[path.concat("dynamic").join(".")] = mappings.dynamic;
|
|
3322
3406
|
}
|
|
3323
3407
|
|
|
3324
3408
|
for (const [key, value] of Object.entries(mappings)) {
|
|
@@ -3336,9 +3420,9 @@ function findDynamic (mappings, path = [], results = {}) {
|
|
|
3336
3420
|
* @param {Object} esRequest
|
|
3337
3421
|
* @throws
|
|
3338
3422
|
*/
|
|
3339
|
-
function assertNoRouting
|
|
3423
|
+
function assertNoRouting(esRequest) {
|
|
3340
3424
|
if (esRequest.body._routing) {
|
|
3341
|
-
throw kerror.get(
|
|
3425
|
+
throw kerror.get("no_routing");
|
|
3342
3426
|
}
|
|
3343
3427
|
}
|
|
3344
3428
|
|
|
@@ -3348,14 +3432,14 @@ function assertNoRouting (esRequest) {
|
|
|
3348
3432
|
* @param {Object} esRequest
|
|
3349
3433
|
* @throws
|
|
3350
3434
|
*/
|
|
3351
|
-
function assertWellFormedRefresh
|
|
3352
|
-
if (!
|
|
3353
|
-
throw kerror.get(
|
|
3435
|
+
function assertWellFormedRefresh(esRequest) {
|
|
3436
|
+
if (!["wait_for", "false", false, undefined].includes(esRequest.refresh)) {
|
|
3437
|
+
throw kerror.get("invalid_argument", "refresh", '"wait_for", false');
|
|
3354
3438
|
}
|
|
3355
3439
|
}
|
|
3356
3440
|
|
|
3357
|
-
function getKuid
|
|
3358
|
-
if (!
|
|
3441
|
+
function getKuid(userId) {
|
|
3442
|
+
if (!userId) {
|
|
3359
3443
|
return null;
|
|
3360
3444
|
}
|
|
3361
3445
|
|
|
@@ -3377,8 +3461,8 @@ function getKuid (userId) {
|
|
|
3377
3461
|
* @param {string} name
|
|
3378
3462
|
* @returns {Boolean}
|
|
3379
3463
|
*/
|
|
3380
|
-
function _isObjectNameValid
|
|
3381
|
-
if (typeof name !==
|
|
3464
|
+
function _isObjectNameValid(name) {
|
|
3465
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
3382
3466
|
return false;
|
|
3383
3467
|
}
|
|
3384
3468
|
|
|
@@ -3390,14 +3474,14 @@ function _isObjectNameValid (name) {
|
|
|
3390
3474
|
return false;
|
|
3391
3475
|
}
|
|
3392
3476
|
|
|
3393
|
-
if (name ===
|
|
3477
|
+
if (name === "_all") {
|
|
3394
3478
|
return false;
|
|
3395
3479
|
}
|
|
3396
3480
|
|
|
3397
3481
|
let valid = true;
|
|
3398
3482
|
|
|
3399
3483
|
for (let i = 0; valid && i < FORBIDDEN_CHARS.length; i++) {
|
|
3400
|
-
valid = !
|
|
3484
|
+
valid = !name.includes(FORBIDDEN_CHARS[i]);
|
|
3401
3485
|
}
|
|
3402
3486
|
|
|
3403
3487
|
return valid;
|