@travetto/model-mongo 6.0.0-rc.0 → 6.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -18
- package/__index__.ts +2 -2
- package/package.json +6 -6
- package/src/internal/util.ts +5 -7
- package/src/service.ts +44 -48
package/README.md
CHANGED
|
@@ -16,15 +16,15 @@ yarn add @travetto/model-mongo
|
|
|
16
16
|
This module provides an [mongodb](https://mongodb.com)-based implementation for 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 [mongodb](https://mongodb.com).. Given the dynamic nature of [mongodb](https://mongodb.com), during development when models are modified, nothing needs to be done to adapt to the latest schema.
|
|
17
17
|
|
|
18
18
|
Supported features:
|
|
19
|
-
* [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/
|
|
20
|
-
* [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/
|
|
21
|
-
* [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/
|
|
22
|
-
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/
|
|
23
|
-
* [Blob](https://github.com/travetto/travetto/tree/main/module/model/src/
|
|
24
|
-
* [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/
|
|
25
|
-
* [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/
|
|
26
|
-
* [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/
|
|
27
|
-
* [Suggest](https://github.com/travetto/travetto/tree/main/module/model-query/src/
|
|
19
|
+
* [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L11)
|
|
20
|
+
* [Expiry](https://github.com/travetto/travetto/tree/main/module/model/src/types/expiry.ts#L10)
|
|
21
|
+
* [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/types/bulk.ts#L64)
|
|
22
|
+
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/types/indexed.ts#L11)
|
|
23
|
+
* [Blob](https://github.com/travetto/travetto/tree/main/module/model/src/types/blob.ts#L8)
|
|
24
|
+
* [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/crud.ts#L11)
|
|
25
|
+
* [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/facet.ts#L14)
|
|
26
|
+
* [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/query.ts#L10)
|
|
27
|
+
* [Suggest](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/suggest.ts#L12)
|
|
28
28
|
Out of the box, by installing the module, everything should be wired up by default.If you need to customize any aspect of the source or config, you can override and register it with the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") module.
|
|
29
29
|
|
|
30
30
|
**Code: Wiring up a custom Model Source**
|
|
@@ -46,15 +46,6 @@ where the [MongoModelConfig](https://github.com/travetto/travetto/tree/main/modu
|
|
|
46
46
|
|
|
47
47
|
**Code: Structure of MongoModelConfig**
|
|
48
48
|
```typescript
|
|
49
|
-
import type mongo from 'mongodb';
|
|
50
|
-
|
|
51
|
-
import { TimeSpan, TimeUtil, RuntimeResources, Runtime } from '@travetto/runtime';
|
|
52
|
-
import { Config } from '@travetto/config';
|
|
53
|
-
import { Field } from '@travetto/schema';
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Mongo model config
|
|
57
|
-
*/
|
|
58
49
|
@Config('model.mongo')
|
|
59
50
|
export class MongoModelConfig {
|
|
60
51
|
/**
|
package/__index__.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from './src/service';
|
|
2
|
-
export * from './src/config';
|
|
1
|
+
export * from './src/service.ts';
|
|
2
|
+
export * from './src/config.ts';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-mongo",
|
|
3
|
-
"version": "6.0.0-rc.
|
|
3
|
+
"version": "6.0.0-rc.2",
|
|
4
4
|
"description": "Mongo backing for the travetto model module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mongo",
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"directory": "module/model-mongo"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@travetto/cli": "^6.0.0-rc.
|
|
29
|
-
"@travetto/config": "^6.0.0-rc.
|
|
30
|
-
"@travetto/model": "^6.0.0-rc.
|
|
31
|
-
"@travetto/model-query": "^6.0.0-rc.
|
|
32
|
-
"mongodb": "^6.
|
|
28
|
+
"@travetto/cli": "^6.0.0-rc.2",
|
|
29
|
+
"@travetto/config": "^6.0.0-rc.2",
|
|
30
|
+
"@travetto/model": "^6.0.0-rc.2",
|
|
31
|
+
"@travetto/model-query": "^6.0.0-rc.2",
|
|
32
|
+
"mongodb": "^6.16.0"
|
|
33
33
|
},
|
|
34
34
|
"travetto": {
|
|
35
35
|
"displayName": "MongoDB Model Support"
|
package/src/internal/util.ts
CHANGED
|
@@ -2,14 +2,12 @@ import {
|
|
|
2
2
|
Binary, type CreateIndexesOptions, type Filter, type FindCursor, type IndexDirection, ObjectId, type WithId as MongoWithId
|
|
3
3
|
} from 'mongodb';
|
|
4
4
|
|
|
5
|
-
import { AppError, castTo, Class, TypedObject } from '@travetto/runtime';
|
|
6
|
-
import type
|
|
5
|
+
import { AppError, castTo, Class, toConcrete, TypedObject } from '@travetto/runtime';
|
|
6
|
+
import { type DistanceUnit, type PageableModelQuery, type WhereClause, ModelQueryUtil } from '@travetto/model-query';
|
|
7
7
|
import type { ModelType, IndexField, IndexConfig } from '@travetto/model';
|
|
8
|
-
import { DataUtil, SchemaRegistry } from '@travetto/schema';
|
|
8
|
+
import { DataUtil, SchemaRegistry, type Point } from '@travetto/schema';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
import { AllViewSymbol } from '@travetto/schema/src/internal/types';
|
|
12
|
-
import { PointImpl } from '@travetto/model-query/src/internal/model/point';
|
|
10
|
+
const PointImpl = toConcrete<Point>();
|
|
13
11
|
|
|
14
12
|
type IdxCfg = CreateIndexesOptions;
|
|
15
13
|
|
|
@@ -89,7 +87,7 @@ export class MongoUtil {
|
|
|
89
87
|
for (const key of keys) {
|
|
90
88
|
const subpath = `${path}${key}`;
|
|
91
89
|
const v: Record<string, unknown> = castTo(sub[key]);
|
|
92
|
-
const subField = schema?.
|
|
90
|
+
const subField = schema?.totalView.schema[key];
|
|
93
91
|
|
|
94
92
|
const isPlain = v && DataUtil.isPlainObject(v);
|
|
95
93
|
const firstKey = isPlain ? Object.keys(v)[0] : '';
|
package/src/service.ts
CHANGED
|
@@ -9,12 +9,14 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
ModelRegistry, ModelType, OptionalId, ModelCrudSupport, ModelStorageSupport,
|
|
11
11
|
ModelExpirySupport, ModelBulkSupport, ModelIndexedSupport, BulkOp, BulkResponse,
|
|
12
|
-
NotFoundError, ExistsError, ModelBlobSupport
|
|
12
|
+
NotFoundError, ExistsError, ModelBlobSupport,
|
|
13
|
+
ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil, ModelBlobUtil,
|
|
13
14
|
} from '@travetto/model';
|
|
14
15
|
import {
|
|
15
16
|
ModelQuery, ModelQueryCrudSupport, ModelQueryFacetSupport, ModelQuerySupport,
|
|
16
17
|
PageableModelQuery, ValidStringFields, WhereClause, ModelQuerySuggestSupport,
|
|
17
|
-
QueryVerifier
|
|
18
|
+
QueryVerifier, ModelQueryUtil, ModelQuerySuggestUtil, ModelQueryCrudUtil,
|
|
19
|
+
ModelQueryFacet,
|
|
18
20
|
} from '@travetto/model-query';
|
|
19
21
|
|
|
20
22
|
import {
|
|
@@ -23,25 +25,17 @@ import {
|
|
|
23
25
|
} from '@travetto/runtime';
|
|
24
26
|
import { Injectable } from '@travetto/di';
|
|
25
27
|
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { ModelStorageUtil } from '@travetto/model/src/internal/service/storage';
|
|
29
|
-
import { ModelQueryUtil } from '@travetto/model-query/src/internal/service/query';
|
|
30
|
-
import { ModelQuerySuggestUtil } from '@travetto/model-query/src/internal/service/suggest';
|
|
31
|
-
import { ModelQueryExpiryUtil } from '@travetto/model-query/src/internal/service/expiry';
|
|
32
|
-
import { ModelExpiryUtil } from '@travetto/model/src/internal/service/expiry';
|
|
33
|
-
import { ModelBulkUtil } from '@travetto/model/src/internal/service/bulk';
|
|
34
|
-
import { MODEL_BLOB, ModelBlobNamespace, ModelBlobUtil } from '@travetto/model/src/internal/service/blob';
|
|
28
|
+
import { MongoUtil, PlainIdx, WithId } from './internal/util.ts';
|
|
29
|
+
import { MongoModelConfig } from './config.ts';
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
import { MongoModelConfig } from './config';
|
|
38
|
-
|
|
39
|
-
const ListIndexSymbol = Symbol.for('@travetto/mongo-model:list-index');
|
|
31
|
+
const ListIndexSymbol = Symbol();
|
|
40
32
|
|
|
41
33
|
type BlobRaw = GridFSFile & { metadata?: BlobMeta };
|
|
42
34
|
|
|
43
35
|
type MongoTextSearch = RootFilterOperators<unknown>['$text'];
|
|
44
36
|
|
|
37
|
+
export const ModelBlobNamespace = '__blobs';
|
|
38
|
+
|
|
45
39
|
/**
|
|
46
40
|
* Mongo-based model source
|
|
47
41
|
*/
|
|
@@ -152,12 +146,12 @@ export class MongoModelService implements
|
|
|
152
146
|
}
|
|
153
147
|
|
|
154
148
|
async truncateModel<T extends ModelType>(cls: Class<T>): Promise<void> {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
149
|
+
const col = await this.getStore(cls);
|
|
150
|
+
await col.deleteMany({});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async truncateBlob(): Promise<void> {
|
|
154
|
+
await this.#bucket.drop().catch(() => { });
|
|
161
155
|
}
|
|
162
156
|
|
|
163
157
|
/**
|
|
@@ -172,9 +166,9 @@ export class MongoModelService implements
|
|
|
172
166
|
const store = await this.getStore(cls);
|
|
173
167
|
const result = await store.findOne(this.getIdFilter(cls, id), {});
|
|
174
168
|
if (result) {
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
177
|
-
return
|
|
169
|
+
const finalized = await this.postLoad(cls, result);
|
|
170
|
+
if (finalized) {
|
|
171
|
+
return finalized;
|
|
178
172
|
}
|
|
179
173
|
}
|
|
180
174
|
throw new NotFoundError(cls, id);
|
|
@@ -196,8 +190,8 @@ export class MongoModelService implements
|
|
|
196
190
|
item = await ModelCrudUtil.preStore(cls, item, this);
|
|
197
191
|
const id = this.preUpdate(item);
|
|
198
192
|
const store = await this.getStore(cls);
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
193
|
+
const result = await store.replaceOne(this.getIdFilter(cls, id), item);
|
|
194
|
+
if (result.matchedCount === 0) {
|
|
201
195
|
throw new NotFoundError(cls, id);
|
|
202
196
|
}
|
|
203
197
|
return this.postUpdate(item, id);
|
|
@@ -243,13 +237,13 @@ export class MongoModelService implements
|
|
|
243
237
|
|
|
244
238
|
const id = item.id;
|
|
245
239
|
|
|
246
|
-
const
|
|
240
|
+
const result = await store.findOneAndUpdate(
|
|
247
241
|
this.getIdFilter(cls, id),
|
|
248
242
|
operation,
|
|
249
243
|
{ returnDocument: 'after', includeResultMetadata: true }
|
|
250
244
|
);
|
|
251
245
|
|
|
252
|
-
if (!
|
|
246
|
+
if (!result.value) {
|
|
253
247
|
throw new NotFoundError(cls, id);
|
|
254
248
|
}
|
|
255
249
|
|
|
@@ -305,8 +299,8 @@ export class MongoModelService implements
|
|
|
305
299
|
}
|
|
306
300
|
|
|
307
301
|
async getBlobMeta(location: string): Promise<BlobMeta> {
|
|
308
|
-
const
|
|
309
|
-
return
|
|
302
|
+
const result = await this.#db.collection<{ metadata: BlobMeta }>(`${ModelBlobNamespace}.files`).findOne({ filename: location });
|
|
303
|
+
return result!.metadata;
|
|
310
304
|
}
|
|
311
305
|
|
|
312
306
|
async deleteBlob(location: string): Promise<void> {
|
|
@@ -360,7 +354,7 @@ export class MongoModelService implements
|
|
|
360
354
|
}
|
|
361
355
|
}
|
|
362
356
|
|
|
363
|
-
const
|
|
357
|
+
const result = await bulk.execute({});
|
|
364
358
|
|
|
365
359
|
// Restore all ids
|
|
366
360
|
for (const op of operations) {
|
|
@@ -370,19 +364,19 @@ export class MongoModelService implements
|
|
|
370
364
|
}
|
|
371
365
|
}
|
|
372
366
|
|
|
373
|
-
for (const [index, _id] of TypedObject.entries<Record<string, string>>(
|
|
367
|
+
for (const [index, _id] of TypedObject.entries<Record<string, string>>(result.upsertedIds)) {
|
|
374
368
|
out.insertedIds.set(+index, MongoUtil.idToString(_id));
|
|
375
369
|
}
|
|
376
370
|
|
|
377
371
|
if (out.counts) {
|
|
378
|
-
out.counts.delete =
|
|
372
|
+
out.counts.delete = result.deletedCount;
|
|
379
373
|
out.counts.update = operations.filter(x => x.update).length;
|
|
380
|
-
out.counts.insert =
|
|
374
|
+
out.counts.insert = result.insertedCount;
|
|
381
375
|
out.counts.upsert = operations.filter(x => x.upsert).length;
|
|
382
376
|
}
|
|
383
377
|
|
|
384
|
-
if (
|
|
385
|
-
out.errors =
|
|
378
|
+
if (result.hasWriteErrors()) {
|
|
379
|
+
out.errors = result.getWriteErrors();
|
|
386
380
|
for (const err of out.errors) {
|
|
387
381
|
const op = operations[err.index];
|
|
388
382
|
const k = TypedObject.keys(op)[0];
|
|
@@ -396,7 +390,7 @@ export class MongoModelService implements
|
|
|
396
390
|
|
|
397
391
|
// Expiry
|
|
398
392
|
deleteExpired<T extends ModelType>(cls: Class<T>): Promise<number> {
|
|
399
|
-
return
|
|
393
|
+
return ModelQueryCrudUtil.deleteExpired(this, cls);
|
|
400
394
|
}
|
|
401
395
|
|
|
402
396
|
// Indexed
|
|
@@ -486,8 +480,8 @@ export class MongoModelService implements
|
|
|
486
480
|
where.id = id;
|
|
487
481
|
|
|
488
482
|
const filter = MongoUtil.extractWhereFilter(cls, where);
|
|
489
|
-
const
|
|
490
|
-
if (
|
|
483
|
+
const result = await col.replaceOne(filter, item);
|
|
484
|
+
if (result.matchedCount === 0) {
|
|
491
485
|
throw new NotFoundError(cls, id);
|
|
492
486
|
}
|
|
493
487
|
return this.postUpdate(item, id);
|
|
@@ -498,8 +492,8 @@ export class MongoModelService implements
|
|
|
498
492
|
|
|
499
493
|
const col = await this.getStore(cls);
|
|
500
494
|
const filter = MongoUtil.extractWhereFilter(cls, query.where, false);
|
|
501
|
-
const
|
|
502
|
-
return
|
|
495
|
+
const result = await col.deleteMany(filter);
|
|
496
|
+
return result.deletedCount ?? 0;
|
|
503
497
|
}
|
|
504
498
|
|
|
505
499
|
async updatePartialByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, data: Partial<T>): Promise<number> {
|
|
@@ -519,12 +513,12 @@ export class MongoModelService implements
|
|
|
519
513
|
}, {});
|
|
520
514
|
|
|
521
515
|
const filter = MongoUtil.extractWhereFilter(cls, query.where);
|
|
522
|
-
const
|
|
523
|
-
return
|
|
516
|
+
const result = await col.updateMany(filter, castTo(final));
|
|
517
|
+
return result.matchedCount;
|
|
524
518
|
}
|
|
525
519
|
|
|
526
520
|
// Facet
|
|
527
|
-
async facet<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, query?: ModelQuery<T>): Promise<
|
|
521
|
+
async facet<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, query?: ModelQuery<T>): Promise<ModelQueryFacet[]> {
|
|
528
522
|
await QueryVerifier.verify(cls, query);
|
|
529
523
|
|
|
530
524
|
const col = await this.getStore(cls);
|
|
@@ -552,10 +546,12 @@ export class MongoModelService implements
|
|
|
552
546
|
|
|
553
547
|
const result = await col.aggregate<{ _id: ObjectId, count: number }>(aggregations).toArray();
|
|
554
548
|
|
|
555
|
-
return result
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
549
|
+
return result
|
|
550
|
+
.map(val => ({
|
|
551
|
+
key: MongoUtil.idToString(val._id),
|
|
552
|
+
count: val.count
|
|
553
|
+
}))
|
|
554
|
+
.toSorted((a, b) => b.count - a.count);
|
|
559
555
|
}
|
|
560
556
|
|
|
561
557
|
// Suggest
|