@travetto/model-elasticsearch 6.0.1 → 7.0.0-rc.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#L30) 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#L29) 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#L11) is defined by:
45
+ where the [ElasticsearchModelConfig](https://github.com/travetto/travetto/tree/main/module/model-elasticsearch/src/config.ts#L10) is defined by:
46
46
 
47
47
  **Code: Structure of ElasticsearchModelConfig**
48
48
  ```typescript
@@ -76,7 +76,6 @@ export class ElasticsearchModelConfig {
76
76
  /**
77
77
  * Base schema config for elasticsearch
78
78
  */
79
- @Field(Object)
80
79
  schemaConfig: EsSchemaConfig = {
81
80
  caseSensitive: false
82
81
  };
@@ -84,7 +83,6 @@ export class ElasticsearchModelConfig {
84
83
  /**
85
84
  * Base index create settings
86
85
  */
87
- @Field(Object)
88
86
  indexCreate = {
89
87
  ['number_of_replicas']: 0,
90
88
  ['number_of_shards']: 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-elasticsearch",
3
- "version": "6.0.1",
3
+ "version": "7.0.0-rc.1",
4
4
  "description": "Elasticsearch backing for the travetto model module, with real-time modeling support for Elasticsearch mappings.",
5
5
  "keywords": [
6
6
  "elasticsearch",
@@ -27,11 +27,11 @@
27
27
  "directory": "module/model-elasticsearch"
28
28
  },
29
29
  "dependencies": {
30
- "@elastic/elasticsearch": "^9.1.1",
31
- "@travetto/cli": "^6.0.1",
32
- "@travetto/config": "^6.0.1",
33
- "@travetto/model": "^6.0.1",
34
- "@travetto/model-query": "^6.0.1"
30
+ "@elastic/elasticsearch": "^9.2.0",
31
+ "@travetto/cli": "^7.0.0-rc.1",
32
+ "@travetto/config": "^7.0.0-rc.1",
33
+ "@travetto/model": "^7.0.0-rc.1",
34
+ "@travetto/model-query": "^7.0.0-rc.1"
35
35
  },
36
36
  "travetto": {
37
37
  "displayName": "Elasticsearch Model Source"
package/src/config.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { TimeSpan } from '@travetto/runtime';
2
2
  import { Config } from '@travetto/config';
3
- import { Field } from '@travetto/schema';
4
3
 
5
4
  import { EsSchemaConfig } from './internal/types.ts';
6
5
 
@@ -37,7 +36,6 @@ export class ElasticsearchModelConfig {
37
36
  /**
38
37
  * Base schema config for elasticsearch
39
38
  */
40
- @Field(Object)
41
39
  schemaConfig: EsSchemaConfig = {
42
40
  caseSensitive: false
43
41
  };
@@ -45,7 +43,6 @@ export class ElasticsearchModelConfig {
45
43
  /**
46
44
  * Base index create settings
47
45
  */
48
- @Field(Object)
49
46
  indexCreate = {
50
47
  ['number_of_replicas']: 0,
51
48
  ['number_of_shards']: 1
@@ -1,8 +1,8 @@
1
1
  import { Client, estypes } from '@elastic/elasticsearch';
2
2
 
3
3
  import { Class } from '@travetto/runtime';
4
- import { ModelRegistry, ModelType, ModelStorageSupport } from '@travetto/model';
5
- import { SchemaChange } from '@travetto/schema';
4
+ import { ModelRegistryIndex, ModelType, ModelStorageSupport } from '@travetto/model';
5
+ import { SchemaChange, SchemaRegistryIndex } from '@travetto/schema';
6
6
 
7
7
  import { ElasticsearchModelConfig } from './config.ts';
8
8
  import { ElasticsearchSchemaUtil } from './internal/schema.ts';
@@ -24,7 +24,7 @@ export class IndexManager implements ModelStorageSupport {
24
24
  }
25
25
 
26
26
  getStore(cls: Class): string {
27
- return ModelRegistry.getStore(cls).toLowerCase().replace(/[^A-Za-z0-9_]+/g, '_');
27
+ return ModelRegistryIndex.getStoreName(cls).toLowerCase().replace(/[^A-Za-z0-9_]+/g, '_');
28
28
  }
29
29
 
30
30
  /**
@@ -98,13 +98,12 @@ export class IndexManager implements ModelStorageSupport {
98
98
  * Build an index if missing
99
99
  */
100
100
  async createIndexIfMissing(cls: Class): Promise<void> {
101
- cls = ModelRegistry.getBaseModel(cls);
102
- const ident = this.getIdentity(cls);
101
+ const baseCls = SchemaRegistryIndex.getBaseClass(cls);
102
+ const ident = this.getIdentity(baseCls);
103
103
  try {
104
104
  await this.#client.search(ident);
105
- console.debug('Index already exists, not creating', ident);
106
105
  } catch {
107
- await this.createIndex(cls);
106
+ await this.createIndex(baseCls);
108
107
  }
109
108
  }
110
109
 
@@ -186,7 +185,7 @@ export class IndexManager implements ModelStorageSupport {
186
185
 
187
186
  await this.#client.indices.putMapping({
188
187
  index,
189
- body: schema
188
+ ...schema,
190
189
  });
191
190
  }
192
191
  }
@@ -2,8 +2,8 @@ import { estypes } from '@elastic/elasticsearch';
2
2
 
3
3
  import { castTo, Class, TypedObject } from '@travetto/runtime';
4
4
  import { WhereClause, SelectClause, SortClause, Query, ModelQueryUtil } from '@travetto/model-query';
5
- import { IndexConfig, ModelType, ModelRegistry } from '@travetto/model';
6
- import { DataUtil, SchemaRegistry } from '@travetto/schema';
5
+ import { IndexConfig, ModelType, ModelRegistryIndex } from '@travetto/model';
6
+ import { DataUtil, SchemaRegistryIndex } from '@travetto/schema';
7
7
 
8
8
  import { EsSchemaConfig } from './types.ts';
9
9
 
@@ -65,11 +65,11 @@ export class ElasticsearchQueryUtil {
65
65
  */
66
66
  static extractWhereTermQuery<T>(cls: Class<T>, o: Record<string, unknown>, config?: EsSchemaConfig, path: string = ''): Record<string, unknown> {
67
67
  const items = [];
68
- const schema = SchemaRegistry.getViewSchema(cls).schema;
68
+ const fields = SchemaRegistryIndex.get(cls).getFields();
69
69
 
70
70
  for (const key of TypedObject.keys(o)) {
71
71
  const top = o[key];
72
- const declaredSchema = schema[key];
72
+ const declaredSchema = fields[key];
73
73
  const declaredType = declaredSchema.type;
74
74
  const sPath = declaredType === String ?
75
75
  ((key === 'id' && !path) ? '_id' : `${path}${key}`) :
@@ -205,11 +205,11 @@ export class ElasticsearchQueryUtil {
205
205
  * @param search
206
206
  */
207
207
  static getSearchQuery<T extends ModelType>(cls: Class<T>, search: Record<string, unknown>, checkExpiry = true): estypes.QueryDslQueryContainer {
208
- const clauses = [];
208
+ const clauses: estypes.QueryDslQueryContainer[] = [];
209
209
  if (search && Object.keys(search).length) {
210
210
  clauses.push(search);
211
211
  }
212
- const { expiresAt, subType } = ModelRegistry.get(cls);
212
+ const { expiresAt } = ModelRegistryIndex.getConfig(cls);
213
213
  if (checkExpiry && expiresAt) {
214
214
  clauses.push({
215
215
  bool: {
@@ -221,11 +221,13 @@ export class ElasticsearchQueryUtil {
221
221
  },
222
222
  });
223
223
  }
224
- if (subType) {
225
- const { subTypeField, subTypeName } = SchemaRegistry.get(cls);
226
- clauses.push({
227
- term: { [subTypeField]: { value: subTypeName } }
228
- });
224
+ const polymorphicConfig = SchemaRegistryIndex.getDiscriminatedConfig(cls);
225
+ if (polymorphicConfig) {
226
+ if (polymorphicConfig.discriminatedBase) {
227
+ clauses.push({ terms: { [polymorphicConfig.discriminatedField]: SchemaRegistryIndex.getDiscriminatedTypes(cls)! } });
228
+ } else {
229
+ clauses.push({ term: { [polymorphicConfig.discriminatedField]: { value: polymorphicConfig.discriminatedType } } });
230
+ }
229
231
  }
230
232
  return clauses.length === 0 ? {} :
231
233
  clauses.length === 1 ? clauses[0] :
@@ -1,8 +1,7 @@
1
1
  import { estypes } from '@elastic/elasticsearch';
2
2
 
3
3
  import { Class, toConcrete } from '@travetto/runtime';
4
- import { ModelRegistry } from '@travetto/model';
5
- import { Point, DataUtil, SchemaRegistry } from '@travetto/schema';
4
+ import { Point, DataUtil, SchemaRegistryIndex } from '@travetto/schema';
6
5
 
7
6
  import { EsSchemaConfig } from './types.ts';
8
7
 
@@ -55,7 +54,7 @@ export class ElasticsearchSchemaUtil {
55
54
  * Build one or more mappings depending on the polymorphic state
56
55
  */
57
56
  static generateSchemaMapping(cls: Class, config?: EsSchemaConfig): estypes.MappingTypeMapping {
58
- return ModelRegistry.get(cls).baseType ?
57
+ return SchemaRegistryIndex.getConfig(cls).discriminatedBase ?
59
58
  this.generateAllMapping(cls, config) :
60
59
  this.generateSingleMapping(cls, config);
61
60
  }
@@ -64,7 +63,7 @@ export class ElasticsearchSchemaUtil {
64
63
  * Generate all mappings
65
64
  */
66
65
  static generateAllMapping(cls: Class, config?: EsSchemaConfig): estypes.MappingTypeMapping {
67
- const allTypes = ModelRegistry.getClassesByBaseType(cls);
66
+ const allTypes = SchemaRegistryIndex.getDiscriminatedClasses(cls);
68
67
  return allTypes.reduce<estypes.MappingTypeMapping>((acc, schemaCls) => {
69
68
  DataUtil.deepAssign(acc, this.generateSingleMapping(schemaCls, config));
70
69
  return acc;
@@ -75,13 +74,11 @@ export class ElasticsearchSchemaUtil {
75
74
  * Build a mapping for a given class
76
75
  */
77
76
  static generateSingleMapping<T>(cls: Class<T>, config?: EsSchemaConfig): estypes.MappingTypeMapping {
78
- const schema = SchemaRegistry.getViewSchema(cls);
77
+ const fields = SchemaRegistryIndex.get(cls).getFields();
79
78
 
80
79
  const props: Record<string, estypes.MappingProperty> = {};
81
80
 
82
- for (const field of schema.fields) {
83
- const conf = schema.schema[field];
84
-
81
+ for (const [field, conf] of Object.entries(fields)) {
85
82
  if (conf.type === PointImpl) {
86
83
  props[field] = { type: 'geo_point' };
87
84
  } else if (conf.type === Number) {
@@ -136,7 +133,7 @@ export class ElasticsearchSchemaUtil {
136
133
  props[field] = { type: 'keyword', ...text };
137
134
  } else if (conf.type === Object) {
138
135
  props[field] = { type: 'object', dynamic: true };
139
- } else if (SchemaRegistry.has(conf.type)) {
136
+ } else if (SchemaRegistryIndex.has(conf.type)) {
140
137
  props[field] = {
141
138
  type: conf.array ? 'nested' : 'object',
142
139
  ...this.generateSingleMapping(conf.type, config)
package/src/service.ts CHANGED
@@ -2,8 +2,8 @@ import { Client, errors, estypes } from '@elastic/elasticsearch';
2
2
 
3
3
  import {
4
4
  ModelCrudSupport, BulkOp, BulkResponse, ModelBulkSupport, ModelExpirySupport,
5
- ModelIndexedSupport, ModelType, ModelStorageSupport, NotFoundError, ModelRegistry, OptionalId,
6
- ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil
5
+ ModelIndexedSupport, ModelType, ModelStorageSupport, NotFoundError, ModelRegistryIndex, OptionalId,
6
+ ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil,
7
7
  } from '@travetto/model';
8
8
  import { ShutdownManager, type DeepPartial, type Class, castTo, asFull, TypedObject, asConstructable } from '@travetto/runtime';
9
9
  import { SchemaChange, BindUtil } from '@travetto/schema';
@@ -16,7 +16,6 @@ import {
16
16
  ModelQueryFacet,
17
17
  } from '@travetto/model-query';
18
18
 
19
-
20
19
  import { ElasticsearchModelConfig } from './config.ts';
21
20
  import { EsBulkError } from './internal/types.ts';
22
21
  import { ElasticsearchQueryUtil } from './internal/query.ts';
@@ -95,7 +94,7 @@ export class ElasticsearchModelService implements
95
94
 
96
95
  item = await ModelCrudUtil.load(cls, item);
97
96
 
98
- const { expiresAt } = ModelRegistry.get(cls);
97
+ const { expiresAt } = ModelRegistryIndex.getConfig(cls);
99
98
 
100
99
  if (expiresAt) {
101
100
  const expiry = ModelExpiryUtil.getExpiryState(cls, item);
@@ -167,7 +166,7 @@ export class ElasticsearchModelService implements
167
166
  ...this.manager.getIdentity(cls),
168
167
  id,
169
168
  refresh: true,
170
- body: clean
169
+ body: castTo<T & { id: never }>(clean)
171
170
  });
172
171
 
173
172
  return this.postUpdate(clean, id);
@@ -184,7 +183,7 @@ export class ElasticsearchModelService implements
184
183
 
185
184
  const id = this.preUpdate(o);
186
185
 
187
- if (ModelRegistry.get(cls).expiresAt) {
186
+ if (ModelRegistryIndex.getConfig(cls).expiresAt) {
188
187
  await this.get(cls, id);
189
188
  }
190
189
 
@@ -193,7 +192,7 @@ export class ElasticsearchModelService implements
193
192
  id,
194
193
  op_type: 'index',
195
194
  refresh: true,
196
- body: o
195
+ body: castTo<T & { id: never }>(o)
197
196
  });
198
197
 
199
198
  return this.postUpdate(o, id);
@@ -209,10 +208,8 @@ export class ElasticsearchModelService implements
209
208
  ...this.manager.getIdentity(cls),
210
209
  id,
211
210
  refresh: true,
212
- body: {
213
- doc: item,
214
- doc_as_upsert: true
215
- }
211
+ doc: item,
212
+ doc_as_upsert: true
216
213
  });
217
214
 
218
215
  return this.postUpdate(item, id);
@@ -230,9 +227,7 @@ export class ElasticsearchModelService implements
230
227
  ...this.manager.getIdentity(cls),
231
228
  id,
232
229
  refresh: true,
233
- body: {
234
- script
235
- }
230
+ script,
236
231
  });
237
232
  } catch (err) {
238
233
  if (err instanceof Error && /document_missing_exception/.test(err.message)) {
@@ -385,7 +380,7 @@ export class ElasticsearchModelService implements
385
380
  }
386
381
 
387
382
  async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body?: DeepPartial<T>): AsyncIterable<T> {
388
- const cfg = ModelRegistry.getIndex(cls, idx, ['sorted', 'unsorted']);
383
+ const cfg = ModelRegistryIndex.getIndex(cls, idx, ['sorted', 'unsorted']);
389
384
  let search = await this.execSearch<T>(cls, {
390
385
  scroll: '2m',
391
386
  size: 100,
@@ -455,7 +450,7 @@ export class ElasticsearchModelService implements
455
450
  }
456
451
  query.where = where;
457
452
 
458
- if (ModelRegistry.get(cls).expiresAt) {
453
+ if (ModelRegistryIndex.getConfig(cls).expiresAt) {
459
454
  await this.get(cls, id);
460
455
  }
461
456
 
@@ -545,17 +540,15 @@ export class ElasticsearchModelService implements
545
540
 
546
541
  const q = ElasticsearchQueryUtil.getSearchObject(cls, query ?? {}, this.config.schemaConfig);
547
542
 
548
- const search = {
549
- body: {
550
- query: q.query ?? { ['match_all']: {} },
551
- aggs: { [field]: { terms: { field, size: 100 } } }
552
- },
543
+ const search: estypes.SearchRequest = {
544
+ query: q.query ?? { ['match_all']: {} },
545
+ aggs: { [field]: { terms: { field, size: 100 } } },
553
546
  size: 0
554
547
  };
555
548
 
556
549
  const result = await this.execSearch(cls, search);
557
550
  const { buckets } = castTo<estypes.AggregationsStringTermsAggregate>('buckets' in result.aggregations![field] ? result.aggregations![field] : { buckets: [] });
558
- const out = Array.isArray(buckets) ? buckets.map(b => ({ key: b.key, count: b.doc_count })) : [];
551
+ const out = Array.isArray(buckets) ? buckets.map(b => ({ key: b.key!.toString(), count: b.doc_count })) : [];
559
552
  return out;
560
553
  }
561
554
  }
@@ -1,6 +1,6 @@
1
1
  import type { ServiceDescriptor } from '@travetto/cli';
2
2
 
3
- const version = '9.1.0';
3
+ const version = '9.2.1';
4
4
 
5
5
  const port = 9200;
6
6