@travetto/model-elasticsearch 7.1.4 → 8.0.0-alpha.1

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 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#L29) will also modify the [elasticsearch](https://elastic.co) schema in real time to minimize impact to development.
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)
@@ -42,7 +42,7 @@ export class Init {
42
42
  }
43
43
  ```
44
44
 
45
- where the [ElasticsearchModelConfig](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch/src/config.ts#L10) is defined by:
45
+ where the [ElasticsearchModelConfig](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch/src/config.ts#L11) is defined by:
46
46
 
47
47
  **Code: Structure of ElasticsearchModelConfig**
48
48
  ```typescript
@@ -96,7 +96,8 @@ export class ElasticsearchModelConfig {
96
96
  /**
97
97
  * Build final hosts
98
98
  */
99
- postConstruct(): void {
99
+ @PostConstruct()
100
+ finalizeConfig(): void {
100
101
  console.debug('Constructed', { config: this });
101
102
  this.hosts = this.hosts
102
103
  .map(host => host.includes(':') ? host : `${host}:${this.port}`)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-elasticsearch",
3
- "version": "7.1.4",
3
+ "version": "8.0.0-alpha.1",
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.0",
32
- "@travetto/config": "^7.1.4",
33
- "@travetto/model": "^7.1.4",
34
- "@travetto/model-query": "^7.1.4"
31
+ "@elastic/elasticsearch": "^9.3.4",
32
+ "@travetto/config": "^8.0.0-alpha.1",
33
+ "@travetto/model": "^8.0.0-alpha.1",
34
+ "@travetto/model-query": "^8.0.0-alpha.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^7.1.4"
37
+ "@travetto/cli": "^8.0.0-alpha.1"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@travetto/cli": {
package/src/config.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { TimeSpan } from '@travetto/runtime';
2
2
  import { Config } from '@travetto/config';
3
+ import { PostConstruct } from '@travetto/di';
3
4
 
4
5
  import type { EsSchemaConfig } from './internal/types.ts';
5
6
 
@@ -56,7 +57,8 @@ export class ElasticsearchModelConfig {
56
57
  /**
57
58
  * Build final hosts
58
59
  */
59
- postConstruct(): void {
60
+ @PostConstruct()
61
+ finalizeConfig(): void {
60
62
  console.debug('Constructed', { config: this });
61
63
  this.hosts = this.hosts
62
64
  .map(host => host.includes(':') ? host : `${host}:${this.port}`)
@@ -1,6 +1,7 @@
1
- import type { Client, estypes } from '@elastic/elasticsearch';
1
+ import type { Client } from '@elastic/elasticsearch';
2
+ import type * as estypes from '@elastic/elasticsearch/api/types';
2
3
 
3
- import type { Class } from '@travetto/runtime';
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
- if (!this.#identities.has(cls)) {
44
+ const result = this.#identities.getOrInsertComputed(cls, () => {
44
45
  const col = this.getStore(cls);
45
46
  const index = this.getNamespacedIndex(col);
46
- this.#identities.set(cls, { index });
47
- }
48
- return { ...this.#identities.get(cls)! };
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 '${JSON.stringify({
82
+ return `curl -XPOST $ES_HOST/${index} -d '${JSONUtil.toUTF8({
82
83
  mappings: schema,
83
84
  settings: this.config.indexCreate
84
85
  })}'`;
@@ -1,4 +1,4 @@
1
- import type { estypes } from '@elastic/elasticsearch';
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';
@@ -1,6 +1,6 @@
1
- import type { estypes } from '@elastic/elasticsearch';
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,13 +1,14 @@
1
- import { Client, errors, type estypes } from '@elastic/elasticsearch';
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
- import { Injectable } from '@travetto/di';
11
+ import { Injectable, PostConstruct } from '@travetto/di';
11
12
  import {
12
13
  type ModelQuery, type ModelQueryCrudSupport, type ModelQueryFacetSupport,
13
14
  type ModelQuerySupport, type PageableModelQuery, type Query, type ValidStringFields,
@@ -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,24 @@ export class ElasticsearchModelService implements
40
48
 
41
49
  constructor(config: ElasticsearchModelConfig) { this.config = config; }
42
50
 
51
+ @PostConstruct()
52
+ async initializeClient(this: ElasticsearchModelService): Promise<void> {
53
+ this.client = new Client({
54
+ nodes: this.config.hosts,
55
+ ...(this.config.options || {}),
56
+ Serializer: class extends Serializer {
57
+ deserialize = JSONUtil.fromUTF8;
58
+ serialize = (obj: unknown): string => JSONUtil.toUTF8(obj, ELASTICSEARCH_REPLACER);
59
+ }
60
+ });
61
+ await this.client.cluster.health({});
62
+ this.manager = new IndexManager(this.config, this.client);
63
+
64
+ await ModelStorageUtil.storageInitialization(this.manager);
65
+ ShutdownManager.signal.addEventListener('abort', () => this.client.close());
66
+ ModelExpiryUtil.registerCull(this);
67
+ }
68
+
43
69
  /**
44
70
  * Directly run the search
45
71
  */
@@ -107,19 +133,6 @@ export class ElasticsearchModelService implements
107
133
  }
108
134
  }
109
135
 
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
136
  createStorage(): Promise<void> { return this.manager.createStorage(); }
124
137
  deleteStorage(): Promise<void> { return this.manager.deleteStorage(); }
125
138
  upsertModel(cls: Class): Promise<void> { return this.manager.upsertModel(cls); }
@@ -157,22 +170,17 @@ export class ElasticsearchModelService implements
157
170
  }
158
171
 
159
172
  async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
160
- try {
161
- const clean = await ModelCrudUtil.preStore(cls, item, this);
162
- const id = this.preUpdate(clean);
173
+ const clean = await ModelCrudUtil.preStore(cls, item, this);
174
+ const id = this.preUpdate(clean);
163
175
 
164
- await this.client.index({
165
- ...this.manager.getIdentity(cls),
166
- id,
167
- refresh: true,
168
- body: castTo<T & { id: never }>(clean)
169
- });
176
+ await this.client.index({
177
+ ...this.manager.getIdentity(cls),
178
+ id,
179
+ refresh: true,
180
+ body: castTo<T & { id: never }>(clean)
181
+ });
170
182
 
171
- return this.postUpdate(clean, id);
172
- } catch (error) {
173
- console.error(error);
174
- throw error;
175
- }
183
+ return this.postUpdate(clean, id);
176
184
  }
177
185
 
178
186
  async update<T extends ModelType>(cls: Class<T>, item: T): Promise<T> {
@@ -531,7 +539,7 @@ export class ElasticsearchModelService implements
531
539
  });
532
540
  const search = ElasticsearchQueryUtil.getSearchObject(cls, resolvedQuery);
533
541
  const result = await this.execSearch(cls, search);
534
- const all = await Promise.all(result.hits.hits.map(hit => castTo<T>(({ [field]: field === 'id' ? hit._id : hit._source![field] }))));
542
+ const all = result.hits.hits.map(hit => castTo<T>(({ [field]: field === 'id' ? hit._id : hit._source![field] })));
535
543
  return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, all, item => item, query && query.limit);
536
544
  }
537
545
 
@@ -1,6 +1,6 @@
1
1
  import type { ServiceDescriptor } from '@travetto/cli';
2
2
 
3
- const version = '9.2.3';
3
+ const version = '9.2.4';
4
4
 
5
5
  const port = 9200;
6
6