@travetto/model-mongo 7.0.0-rc.2 → 7.0.0-rc.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/README.md +2 -2
- package/package.json +5 -5
- package/src/config.ts +2 -2
- package/src/internal/util.ts +31 -1
- package/src/service.ts +28 -17
package/README.md
CHANGED
|
@@ -84,9 +84,9 @@ export class MongoModelConfig {
|
|
|
84
84
|
options: mongo.MongoClientOptions = {};
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
87
|
+
* Allow storage modification at runtime
|
|
88
88
|
*/
|
|
89
|
-
|
|
89
|
+
modifyStorage?: boolean;
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Frequency of culling for cullable content
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-mongo",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.3",
|
|
4
4
|
"description": "Mongo backing for the travetto model module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mongo",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"directory": "module/model-mongo"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@travetto/cli": "^7.0.0-rc.
|
|
29
|
-
"@travetto/config": "^7.0.0-rc.
|
|
30
|
-
"@travetto/model": "^7.0.0-rc.
|
|
31
|
-
"@travetto/model-query": "^7.0.0-rc.
|
|
28
|
+
"@travetto/cli": "^7.0.0-rc.3",
|
|
29
|
+
"@travetto/config": "^7.0.0-rc.3",
|
|
30
|
+
"@travetto/model": "^7.0.0-rc.3",
|
|
31
|
+
"@travetto/model-query": "^7.0.0-rc.3",
|
|
32
32
|
"mongodb": "^7.0.0"
|
|
33
33
|
},
|
|
34
34
|
"travetto": {
|
package/src/config.ts
CHANGED
|
@@ -43,9 +43,9 @@ export class MongoModelConfig {
|
|
|
43
43
|
options: mongo.MongoClientOptions = {};
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
46
|
+
* Allow storage modification at runtime
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
modifyStorage?: boolean;
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Frequency of culling for cullable content
|
package/src/internal/util.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Binary, type CreateIndexesOptions, type Filter, type FindCursor, type IndexDirection, ObjectId, type WithId as MongoWithId
|
|
2
|
+
Binary, type CreateIndexesOptions, type Filter, type FindCursor, type IndexDirection, ObjectId, type WithId as MongoWithId,
|
|
3
|
+
type IndexDescriptionInfo
|
|
3
4
|
} from 'mongodb';
|
|
4
5
|
|
|
5
6
|
import { AppError, castTo, Class, toConcrete, TypedObject } from '@travetto/runtime';
|
|
@@ -212,4 +213,33 @@ export class MongoUtil {
|
|
|
212
213
|
|
|
213
214
|
return castTo(cursor);
|
|
214
215
|
}
|
|
216
|
+
|
|
217
|
+
static isIndexChanged(existing: IndexDescriptionInfo, [pendingKey, pendingOptions]: [BasicIdx, CreateIndexesOptions]): boolean {
|
|
218
|
+
// Config changed
|
|
219
|
+
if (
|
|
220
|
+
!!existing.unique !== !!pendingOptions.unique ||
|
|
221
|
+
!!existing.sparse !== !!pendingOptions.sparse ||
|
|
222
|
+
existing.expireAfterSeconds !== pendingOptions.expireAfterSeconds ||
|
|
223
|
+
existing.bucketSize !== pendingOptions.bucketSize
|
|
224
|
+
) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
const pendingKeySet = new Set(Object.keys(pendingKey));
|
|
228
|
+
const existingKeySet = new Set(Object.keys(existing.key));
|
|
229
|
+
|
|
230
|
+
if (pendingKeySet.size !== existingKeySet.size) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const overlap = pendingKeySet.intersection(existingKeySet);
|
|
235
|
+
if (overlap.size !== pendingKeySet.size) {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
for (const key of overlap) {
|
|
239
|
+
if (existing.key[key] !== pendingKey[key]) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
215
245
|
}
|
package/src/service.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { pipeline } from 'node:stream/promises';
|
|
|
3
3
|
import {
|
|
4
4
|
type Db, GridFSBucket, MongoClient, type GridFSFile, type Collection,
|
|
5
5
|
type ObjectId, type Binary, type RootFilterOperators, type Filter,
|
|
6
|
-
type WithId as MongoWithId
|
|
6
|
+
type WithId as MongoWithId,
|
|
7
7
|
} from 'mongodb';
|
|
8
8
|
|
|
9
9
|
import {
|
|
@@ -106,7 +106,7 @@ export class MongoModelService implements
|
|
|
106
106
|
bucketName: ModelBlobNamespace,
|
|
107
107
|
writeConcern: { w: 1 }
|
|
108
108
|
});
|
|
109
|
-
await ModelStorageUtil.
|
|
109
|
+
await ModelStorageUtil.storageInitialization(this);
|
|
110
110
|
ShutdownManager.onGracefulShutdown(() => this.client.close());
|
|
111
111
|
ModelExpiryUtil.registerCull(this);
|
|
112
112
|
}
|
|
@@ -126,23 +126,34 @@ export class MongoModelService implements
|
|
|
126
126
|
await this.#db.dropDatabase();
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
async
|
|
129
|
+
async upsertModel(cls: Class): Promise<void> {
|
|
130
130
|
const col = await this.getStore(cls);
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
console.debug('Creating indexes', { indices: creating });
|
|
134
|
-
for (const toCreate of creating) {
|
|
135
|
-
await col.createIndex(...toCreate);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
131
|
+
const indices = MongoUtil.getIndices(cls, ModelRegistryIndex.getConfig(cls).indices);
|
|
132
|
+
const existingIndices = (await col.indexes().catch(() => [])).filter(idx => idx.name !== '_id_');
|
|
139
133
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
134
|
+
const pendingMap = Object.fromEntries(indices.map(pair => [pair[1].name!, pair]));
|
|
135
|
+
const existingMap = Object.fromEntries(existingIndices.map(idx => [idx.name!, idx.key]));
|
|
143
136
|
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
for (const idx of existingIndices) {
|
|
138
|
+
if (!idx.name) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const pending = pendingMap[idx.name];
|
|
142
|
+
if (!pending) {
|
|
143
|
+
console.debug('Deleting index', { indices: idx.name });
|
|
144
|
+
await col.dropIndex(idx.name);
|
|
145
|
+
} else if (MongoUtil.isIndexChanged(idx, pending)) {
|
|
146
|
+
console.debug('Updating index', { indices: idx.name });
|
|
147
|
+
await col.dropIndex(idx.name);
|
|
148
|
+
await col.createIndex(...pending);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
for (const [name, idx] of Object.entries(pendingMap)) {
|
|
152
|
+
if (!existingMap[name]) {
|
|
153
|
+
console.debug('Creating index', { indices: name });
|
|
154
|
+
await col.createIndex(...idx);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
async truncateModel<T extends ModelType>(cls: Class<T>): Promise<void> {
|
|
@@ -158,7 +169,7 @@ export class MongoModelService implements
|
|
|
158
169
|
* Get mongo collection
|
|
159
170
|
*/
|
|
160
171
|
async getStore<T extends ModelType>(cls: Class<T>): Promise<Collection<T>> {
|
|
161
|
-
return this.#db.collection(ModelRegistryIndex.getStoreName(cls)
|
|
172
|
+
return this.#db.collection(ModelRegistryIndex.getStoreName(cls));
|
|
162
173
|
}
|
|
163
174
|
|
|
164
175
|
// Crud
|