@travetto/model-elasticsearch 7.1.3 → 8.0.0-alpha.0
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/README.md +1 -1
- package/package.json +6 -6
- package/src/index-manager.ts +8 -7
- package/src/internal/query.ts +1 -1
- package/src/internal/schema.ts +4 -2
- package/src/service.ts +37 -30
- package/support/service.elasticsearch.ts +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @travetto/model-elasticsearch
|
|
|
13
13
|
yarn add @travetto/model-elasticsearch
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
This module provides an [elasticsearch](https://elastic.co)-based implementation of the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."). This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [elasticsearch](https://elastic.co). In development mode, [ElasticsearchModelService](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch/src/service.ts#
|
|
16
|
+
This module provides an [elasticsearch](https://elastic.co)-based implementation of the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."). This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [elasticsearch](https://elastic.co). In development mode, [ElasticsearchModelService](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch/src/service.ts#L36) will also modify the [elasticsearch](https://elastic.co) schema in real time to minimize impact to development.
|
|
17
17
|
|
|
18
18
|
Supported features:
|
|
19
19
|
* [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L11)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-elasticsearch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0-alpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Elasticsearch backing for the travetto model module, with real-time modeling support for Elasticsearch mappings.",
|
|
6
6
|
"keywords": [
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"directory": "module/model-elasticsearch"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@elastic/elasticsearch": "^9.2
|
|
32
|
-
"@travetto/config": "^
|
|
33
|
-
"@travetto/model": "^
|
|
34
|
-
"@travetto/model-query": "^
|
|
31
|
+
"@elastic/elasticsearch": "^9.3.2",
|
|
32
|
+
"@travetto/config": "^8.0.0-alpha.0",
|
|
33
|
+
"@travetto/model": "^8.0.0-alpha.0",
|
|
34
|
+
"@travetto/model-query": "^8.0.0-alpha.0"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@travetto/cli": "^
|
|
37
|
+
"@travetto/cli": "^8.0.0-alpha.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
40
|
"@travetto/cli": {
|
package/src/index-manager.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { Client
|
|
1
|
+
import type { Client } from '@elastic/elasticsearch';
|
|
2
|
+
import type * as estypes from '@elastic/elasticsearch/api/types';
|
|
2
3
|
|
|
3
|
-
import type
|
|
4
|
+
import { JSONUtil, type Class } from '@travetto/runtime';
|
|
4
5
|
import { ModelRegistryIndex, type ModelType, type ModelStorageSupport } from '@travetto/model';
|
|
5
6
|
|
|
6
7
|
import type { ElasticsearchModelConfig } from './config.ts';
|
|
@@ -40,12 +41,12 @@ export class IndexManager implements ModelStorageSupport {
|
|
|
40
41
|
* Build the elasticsearch identity set for a given class (index)
|
|
41
42
|
*/
|
|
42
43
|
getIdentity<T extends ModelType>(cls: Class<T>): { index: string } {
|
|
43
|
-
|
|
44
|
+
const result = this.#identities.getOrInsertComputed(cls, () => {
|
|
44
45
|
const col = this.getStore(cls);
|
|
45
46
|
const index = this.getNamespacedIndex(col);
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return { ...
|
|
47
|
+
return { index };
|
|
48
|
+
});
|
|
49
|
+
return { ...result };
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|
|
@@ -78,7 +79,7 @@ export class IndexManager implements ModelStorageSupport {
|
|
|
78
79
|
async exportModel(cls: Class<ModelType>): Promise<string> {
|
|
79
80
|
const schema = ElasticsearchSchemaUtil.generateSchemaMapping(cls, this.config.schemaConfig);
|
|
80
81
|
const { index } = this.getIdentity(cls); // Already namespaced
|
|
81
|
-
return `curl -XPOST $ES_HOST/${index} -d '${
|
|
82
|
+
return `curl -XPOST $ES_HOST/${index} -d '${JSONUtil.toUTF8({
|
|
82
83
|
mappings: schema,
|
|
83
84
|
settings: this.config.indexCreate
|
|
84
85
|
})}'`;
|
package/src/internal/query.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type * as estypes from '@elastic/elasticsearch/api/types';
|
|
2
2
|
|
|
3
3
|
import { castTo, type Class, TypedObject } from '@travetto/runtime';
|
|
4
4
|
import { type WhereClause, type SelectClause, type SortClause, type Query, ModelQueryUtil } from '@travetto/model-query';
|
package/src/internal/schema.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type * as estypes from '@elastic/elasticsearch/api/types';
|
|
2
2
|
|
|
3
|
-
import { type Class, toConcrete } from '@travetto/runtime';
|
|
3
|
+
import { castTo, type Class, toConcrete } from '@travetto/runtime';
|
|
4
4
|
import { type Point, DataUtil, SchemaRegistryIndex } from '@travetto/schema';
|
|
5
5
|
|
|
6
6
|
import type { EsSchemaConfig } from './types.ts';
|
|
@@ -84,6 +84,8 @@ export class ElasticsearchSchemaUtil {
|
|
|
84
84
|
for (const [field, config] of Object.entries(fields)) {
|
|
85
85
|
if (config.type === PointConcrete) {
|
|
86
86
|
properties[field] = { type: 'geo_point' };
|
|
87
|
+
} else if (config.type === castTo(BigInt)) {
|
|
88
|
+
properties[field] = { type: 'long' };
|
|
87
89
|
} else if (config.type === Number) {
|
|
88
90
|
let property: Record<string, unknown> = { type: 'integer' };
|
|
89
91
|
if (config.precision) {
|
package/src/service.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { Client, errors,
|
|
1
|
+
import { Client, errors, Serializer } from '@elastic/elasticsearch';
|
|
2
|
+
import type * as estypes from '@elastic/elasticsearch/api/types';
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
5
|
type ModelCrudSupport, type BulkOperation, type BulkResponse, type ModelBulkSupport, type ModelExpirySupport,
|
|
5
6
|
type ModelIndexedSupport, type ModelType, type ModelStorageSupport, NotFoundError, ModelRegistryIndex, type OptionalId,
|
|
6
7
|
ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil,
|
|
7
8
|
} from '@travetto/model';
|
|
8
|
-
import { ShutdownManager, type DeepPartial, type Class, castTo, asFull, TypedObject, asConstructable } from '@travetto/runtime';
|
|
9
|
+
import { ShutdownManager, type DeepPartial, type Class, castTo, asFull, TypedObject, asConstructable, JSONUtil } from '@travetto/runtime';
|
|
9
10
|
import { BindUtil } from '@travetto/schema';
|
|
10
11
|
import { Injectable } from '@travetto/di';
|
|
11
12
|
import {
|
|
@@ -22,6 +23,13 @@ import { ElasticsearchQueryUtil } from './internal/query.ts';
|
|
|
22
23
|
import { ElasticsearchSchemaUtil } from './internal/schema.ts';
|
|
23
24
|
import { IndexManager } from './index-manager.ts';
|
|
24
25
|
|
|
26
|
+
const ELASTICSEARCH_REPLACER = {
|
|
27
|
+
replacer(this: unknown, key: string, value: unknown): unknown {
|
|
28
|
+
// @ts-expect-error
|
|
29
|
+
return (typeof this[key] === 'bigint' ? this[key].toString() : value);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
25
33
|
/**
|
|
26
34
|
* Elasticsearch model source.
|
|
27
35
|
*/
|
|
@@ -40,6 +48,23 @@ export class ElasticsearchModelService implements
|
|
|
40
48
|
|
|
41
49
|
constructor(config: ElasticsearchModelConfig) { this.config = config; }
|
|
42
50
|
|
|
51
|
+
async postConstruct(this: ElasticsearchModelService): Promise<void> {
|
|
52
|
+
this.client = new Client({
|
|
53
|
+
nodes: this.config.hosts,
|
|
54
|
+
...(this.config.options || {}),
|
|
55
|
+
Serializer: class extends Serializer {
|
|
56
|
+
deserialize = JSONUtil.fromUTF8;
|
|
57
|
+
serialize = (obj: unknown): string => JSONUtil.toUTF8(obj, ELASTICSEARCH_REPLACER);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
await this.client.cluster.health({});
|
|
61
|
+
this.manager = new IndexManager(this.config, this.client);
|
|
62
|
+
|
|
63
|
+
await ModelStorageUtil.storageInitialization(this.manager);
|
|
64
|
+
ShutdownManager.signal.addEventListener('abort', () => this.client.close());
|
|
65
|
+
ModelExpiryUtil.registerCull(this);
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
/**
|
|
44
69
|
* Directly run the search
|
|
45
70
|
*/
|
|
@@ -107,19 +132,6 @@ export class ElasticsearchModelService implements
|
|
|
107
132
|
}
|
|
108
133
|
}
|
|
109
134
|
|
|
110
|
-
async postConstruct(this: ElasticsearchModelService): Promise<void> {
|
|
111
|
-
this.client = new Client({
|
|
112
|
-
nodes: this.config.hosts,
|
|
113
|
-
...(this.config.options || {}),
|
|
114
|
-
});
|
|
115
|
-
await this.client.cluster.health({});
|
|
116
|
-
this.manager = new IndexManager(this.config, this.client);
|
|
117
|
-
|
|
118
|
-
await ModelStorageUtil.storageInitialization(this.manager);
|
|
119
|
-
ShutdownManager.signal.addEventListener('abort', () => this.client.close());
|
|
120
|
-
ModelExpiryUtil.registerCull(this);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
135
|
createStorage(): Promise<void> { return this.manager.createStorage(); }
|
|
124
136
|
deleteStorage(): Promise<void> { return this.manager.deleteStorage(); }
|
|
125
137
|
upsertModel(cls: Class): Promise<void> { return this.manager.upsertModel(cls); }
|
|
@@ -157,22 +169,17 @@ export class ElasticsearchModelService implements
|
|
|
157
169
|
}
|
|
158
170
|
|
|
159
171
|
async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const id = this.preUpdate(clean);
|
|
172
|
+
const clean = await ModelCrudUtil.preStore(cls, item, this);
|
|
173
|
+
const id = this.preUpdate(clean);
|
|
163
174
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
175
|
+
await this.client.index({
|
|
176
|
+
...this.manager.getIdentity(cls),
|
|
177
|
+
id,
|
|
178
|
+
refresh: true,
|
|
179
|
+
body: castTo<T & { id: never }>(clean)
|
|
180
|
+
});
|
|
170
181
|
|
|
171
|
-
|
|
172
|
-
} catch (error) {
|
|
173
|
-
console.error(error);
|
|
174
|
-
throw error;
|
|
175
|
-
}
|
|
182
|
+
return this.postUpdate(clean, id);
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
async update<T extends ModelType>(cls: Class<T>, item: T): Promise<T> {
|
|
@@ -531,7 +538,7 @@ export class ElasticsearchModelService implements
|
|
|
531
538
|
});
|
|
532
539
|
const search = ElasticsearchQueryUtil.getSearchObject(cls, resolvedQuery);
|
|
533
540
|
const result = await this.execSearch(cls, search);
|
|
534
|
-
const all =
|
|
541
|
+
const all = result.hits.hits.map(hit => castTo<T>(({ [field]: field === 'id' ? hit._id : hit._source![field] })));
|
|
535
542
|
return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, all, item => item, query && query.limit);
|
|
536
543
|
}
|
|
537
544
|
|