@lossless.org/client 1.6.0 → 1.8.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/nosqldb/classes.atomicdelete.d.ts +1 -0
- package/dist_ts/nosqldb/classes.atomicdelete.js +10 -7
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +2 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +9 -5
- package/dist_ts/nosqldb/classes.atomicupdate.d.ts +2 -0
- package/dist_ts/nosqldb/classes.atomicupdate.js +13 -8
- package/dist_ts/nosqldb/classes.collection.d.ts +13 -4
- package/dist_ts/nosqldb/classes.collection.js +57 -64
- package/dist_ts/nosqldb/classes.db.d.ts +1 -1
- package/dist_ts/nosqldb/classes.doc.d.ts +60 -3
- package/dist_ts/nosqldb/classes.doc.js +68 -26
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +36 -7
- package/dist_ts/nosqldb/classes.exactpersistence.js +92 -81
- package/dist_ts/nosqldb/classes.operationdeadline.d.ts +61 -0
- package/dist_ts/nosqldb/classes.operationdeadline.js +149 -0
- package/dist_ts/nosqldb/classes.persistence.d.ts +16 -1
- package/dist_ts/nosqldb/classes.persistence.js +20 -1
- package/dist_ts/nosqldb/classes.session.d.ts +73 -2
- package/dist_ts/nosqldb/classes.session.js +164 -38
- package/dist_ts/objectstorage/classes.bucket.d.ts +61 -3
- package/dist_ts/objectstorage/classes.bucket.js +243 -184
- package/dist_ts/objectstorage/classes.directory.js +17 -28
- package/dist_ts/objectstorage/classes.smartbucket.d.ts +13 -6
- package/dist_ts/objectstorage/classes.smartbucket.js +18 -12
- package/dist_ts/objectstorage/classes.watcher.js +1 -2
- package/dist_ts/objectstorage/interfaces.d.ts +8 -0
- package/dist_ts/objectstorage/internal.bucketrequests.d.ts +14 -0
- package/dist_ts/objectstorage/internal.bucketrequests.js +53 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +12 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.js +46 -17
- package/package.json +3 -3
- package/readme.md +13 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/nosqldb/classes.atomicdelete.ts +10 -6
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +10 -4
- package/ts/nosqldb/classes.atomicupdate.ts +14 -7
- package/ts/nosqldb/classes.collection.ts +82 -73
- package/ts/nosqldb/classes.db.ts +1 -1
- package/ts/nosqldb/classes.doc.ts +162 -33
- package/ts/nosqldb/classes.exactpersistence.ts +131 -93
- package/ts/nosqldb/classes.operationdeadline.ts +179 -0
- package/ts/nosqldb/classes.persistence.ts +36 -1
- package/ts/nosqldb/classes.session.ts +221 -39
- package/ts/objectstorage/classes.bucket.ts +350 -218
- package/ts/objectstorage/classes.directory.ts +18 -27
- package/ts/objectstorage/classes.smartbucket.ts +21 -11
- package/ts/objectstorage/classes.watcher.ts +0 -1
- package/ts/objectstorage/interfaces.ts +9 -0
- package/ts/objectstorage/internal.bucketrequests.ts +70 -0
- package/ts/objectstorage/internal.exactupload.capability.ts +105 -24
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
import { SmartdataDbWatcher } from './classes.watcher.js';
|
|
26
26
|
import { SmartdataLuceneAdapter } from './classes.lucene.adapter.js';
|
|
27
27
|
import { executeAtomicDelete, executeAtomicDeleteMany } from './classes.atomicdelete.js';
|
|
28
|
+
import { requireOperationSignal } from './classes.operationdeadline.js';
|
|
28
29
|
import {
|
|
29
30
|
executeAtomicFindOneAndReplace, executeAtomicFindOneAndUpdate,
|
|
30
31
|
} from './classes.atomicfindoneandupdate.js';
|
|
@@ -664,7 +665,14 @@ export interface ISmartdataOffsetPageOptions<T> {
|
|
|
664
665
|
projection?: TSmartdataProjection<T>;
|
|
665
666
|
hint?: string;
|
|
666
667
|
maxTimeMS?: number;
|
|
667
|
-
/**
|
|
668
|
+
/**
|
|
669
|
+
* Defaults to 5000ms; maximum 120000ms. Covers the cursor up to its last
|
|
670
|
+
* reply. A page larger than the first batch that stalls in its `getMore`
|
|
671
|
+
* settles within about twice the deadline: the driver's `killCursors` runs
|
|
672
|
+
* on a fresh deadline of the same length before the error surfaces.
|
|
673
|
+
* Inside a transaction with its own deadline that deadline replaces the
|
|
674
|
+
* default, and an explicit value is refused.
|
|
675
|
+
*/
|
|
668
676
|
timeoutMS?: number;
|
|
669
677
|
signal?: AbortSignal;
|
|
670
678
|
session?: TSmartdataOrdinarySession;
|
|
@@ -673,6 +681,8 @@ export interface ISmartdataOffsetPageOptions<T> {
|
|
|
673
681
|
export interface ISmartdataFindOneOptions<T> {
|
|
674
682
|
projection?: TSmartdataProjection<T>;
|
|
675
683
|
maxTimeMS?: number;
|
|
684
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
685
|
+
timeoutMS?: number;
|
|
676
686
|
session?: TSmartdataOrdinarySession;
|
|
677
687
|
}
|
|
678
688
|
|
|
@@ -765,7 +775,12 @@ export interface ISmartdataGroupedTotalsOptions<T> {
|
|
|
765
775
|
*/
|
|
766
776
|
limit: number;
|
|
767
777
|
maxTimeMS?: number;
|
|
768
|
-
/**
|
|
778
|
+
/**
|
|
779
|
+
* Client-side deadline for the aggregation cursor up to its last reply. More
|
|
780
|
+
* groups than the first batch holds need a `getMore`; when that times out the
|
|
781
|
+
* driver's `killCursors` runs on a fresh deadline of the same length, so a
|
|
782
|
+
* stalled database settles the call within about twice the deadline.
|
|
783
|
+
*/
|
|
769
784
|
timeoutMS?: number;
|
|
770
785
|
signal?: AbortSignal;
|
|
771
786
|
session?: TSmartdataOrdinarySession;
|
|
@@ -943,6 +958,8 @@ export type TSmartdataAtomicFilter<T> =
|
|
|
943
958
|
export interface ISmartdataAtomicUpdateOptions {
|
|
944
959
|
upsert?: boolean;
|
|
945
960
|
session?: TSmartdataOrdinarySession;
|
|
961
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
962
|
+
timeoutMS?: number;
|
|
946
963
|
}
|
|
947
964
|
|
|
948
965
|
export interface ISmartdataAtomicUpdateResult {
|
|
@@ -969,6 +986,8 @@ export interface ISmartdataAtomicFindOneAndUpdateOptions<
|
|
|
969
986
|
*/
|
|
970
987
|
sort?: TSmartdataSort<TModel>;
|
|
971
988
|
session?: TSmartdataOrdinarySession;
|
|
989
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
990
|
+
timeoutMS?: number;
|
|
972
991
|
}
|
|
973
992
|
|
|
974
993
|
export type TSmartdataAtomicFindOneAndUpdateResult<
|
|
@@ -989,6 +1008,8 @@ export interface ISmartdataAtomicFindOneAndReplaceOptions {
|
|
|
989
1008
|
*/
|
|
990
1009
|
returnDocument?: TSmartdataAtomicReturnDocument;
|
|
991
1010
|
session?: TSmartdataOrdinarySession;
|
|
1011
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
1012
|
+
timeoutMS?: number;
|
|
992
1013
|
}
|
|
993
1014
|
|
|
994
1015
|
export interface ISmartdataAtomicDeleteOptions {
|
|
@@ -997,6 +1018,14 @@ export interface ISmartdataAtomicDeleteOptions {
|
|
|
997
1018
|
timeoutMS?: number;
|
|
998
1019
|
}
|
|
999
1020
|
|
|
1021
|
+
export interface ISmartdataAtomicDeleteManyOptions extends ISmartdataAtomicDeleteOptions {
|
|
1022
|
+
/**
|
|
1023
|
+
* Cancels the call. An abort before the delete is sent deletes nothing; an
|
|
1024
|
+
* abort in flight closes the connection and leaves the outcome unknown.
|
|
1025
|
+
*/
|
|
1026
|
+
signal?: AbortSignal;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1000
1029
|
export interface ISmartdataInsertManyIfAbsentOptions<T> {
|
|
1001
1030
|
/** A declared, non-serialized @unI identity field. */
|
|
1002
1031
|
identityField: TSmartdataDocumentPath<T>;
|
|
@@ -1017,6 +1046,8 @@ export interface ISmartdataAtomicDeleteResult {
|
|
|
1017
1046
|
|
|
1018
1047
|
export interface ISmartdataAtomicUpdateManyOptions {
|
|
1019
1048
|
session?: TSmartdataOrdinarySession;
|
|
1049
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
1050
|
+
timeoutMS?: number;
|
|
1020
1051
|
}
|
|
1021
1052
|
|
|
1022
1053
|
export interface ISmartdataAtomicUpdateManyResult {
|
|
@@ -1062,6 +1093,8 @@ export interface ISmartdataSaveIfOptions {
|
|
|
1062
1093
|
session?: TSmartdataOrdinarySession;
|
|
1063
1094
|
/** Defaults to `'ignore'`. */
|
|
1064
1095
|
absentDeclaredFields?: TSmartdataAbsentDeclaredFields;
|
|
1096
|
+
/** Client-side deadline for the write (1..120000 ms); `beforeSave()` and `afterSave()` run outside it. */
|
|
1097
|
+
timeoutMS?: number;
|
|
1065
1098
|
}
|
|
1066
1099
|
|
|
1067
1100
|
export interface ISmartdataSaveIfResult {
|
|
@@ -1076,6 +1109,7 @@ const normalizeSaveIfOptions = (
|
|
|
1076
1109
|
): {
|
|
1077
1110
|
session?: TSmartdataOrdinarySession;
|
|
1078
1111
|
absentDeclaredFields: TSmartdataAbsentDeclaredFields;
|
|
1112
|
+
timeoutMS?: number;
|
|
1079
1113
|
} => {
|
|
1080
1114
|
if (optionsArg === undefined) {
|
|
1081
1115
|
return { absentDeclaredFields: 'ignore' };
|
|
@@ -1091,7 +1125,7 @@ const normalizeSaveIfOptions = (
|
|
|
1091
1125
|
'Fenced save options must be an inert plain object.',
|
|
1092
1126
|
);
|
|
1093
1127
|
}
|
|
1094
|
-
const allowedKeys = new Set(['session', 'absentDeclaredFields']);
|
|
1128
|
+
const allowedKeys = new Set(['session', 'absentDeclaredFields', 'timeoutMS']);
|
|
1095
1129
|
for (const key of Reflect.ownKeys(optionsArg)) {
|
|
1096
1130
|
if (typeof key !== 'string' || !allowedKeys.has(key)) {
|
|
1097
1131
|
throw new SmartdataPersistenceError(
|
|
@@ -1124,9 +1158,15 @@ const normalizeSaveIfOptions = (
|
|
|
1124
1158
|
const session = Object.getOwnPropertyDescriptor(optionsArg, 'session')?.value as
|
|
1125
1159
|
| TSmartdataOrdinarySession
|
|
1126
1160
|
| undefined;
|
|
1161
|
+
const timeoutMS = requireBoundedInteger(
|
|
1162
|
+
Object.getOwnPropertyDescriptor(optionsArg, 'timeoutMS')?.value,
|
|
1163
|
+
'Fenced save timeoutMS',
|
|
1164
|
+
120_000,
|
|
1165
|
+
);
|
|
1127
1166
|
return {
|
|
1128
1167
|
...(session !== undefined ? { session } : {}),
|
|
1129
1168
|
absentDeclaredFields: absentDeclaredFields ?? 'ignore',
|
|
1169
|
+
...(timeoutMS !== undefined ? { timeoutMS } : {}),
|
|
1130
1170
|
};
|
|
1131
1171
|
};
|
|
1132
1172
|
|
|
@@ -1139,6 +1179,7 @@ const normalizeAtomicFindOneAndUpdateOptions = <
|
|
|
1139
1179
|
upsert: boolean;
|
|
1140
1180
|
sort?: unknown;
|
|
1141
1181
|
session?: TSmartdataOrdinarySession;
|
|
1182
|
+
timeoutMS?: number;
|
|
1142
1183
|
} => {
|
|
1143
1184
|
if (
|
|
1144
1185
|
typeof optionsArg !== 'object'
|
|
@@ -1151,7 +1192,7 @@ const normalizeAtomicFindOneAndUpdateOptions = <
|
|
|
1151
1192
|
'Atomic find-one-and-update options must be an inert plain object.',
|
|
1152
1193
|
);
|
|
1153
1194
|
}
|
|
1154
|
-
const allowedKeys = new Set(['returnDocument', 'upsert', 'sort', 'session']);
|
|
1195
|
+
const allowedKeys = new Set(['returnDocument', 'upsert', 'sort', 'session', 'timeoutMS']);
|
|
1155
1196
|
const keys = Reflect.ownKeys(optionsArg);
|
|
1156
1197
|
for (const key of keys) {
|
|
1157
1198
|
if (typeof key !== 'string' || !allowedKeys.has(key)) {
|
|
@@ -1195,6 +1236,11 @@ const normalizeAtomicFindOneAndUpdateOptions = <
|
|
|
1195
1236
|
}
|
|
1196
1237
|
const sortDescriptor = Object.getOwnPropertyDescriptor(optionsArg, 'sort');
|
|
1197
1238
|
const sessionDescriptor = Object.getOwnPropertyDescriptor(optionsArg, 'session');
|
|
1239
|
+
const timeoutMS = requireBoundedInteger(
|
|
1240
|
+
Object.getOwnPropertyDescriptor(optionsArg, 'timeoutMS')?.value,
|
|
1241
|
+
'Atomic find-one-and-update timeoutMS',
|
|
1242
|
+
120_000,
|
|
1243
|
+
);
|
|
1198
1244
|
return {
|
|
1199
1245
|
returnDocument: returnDocumentDescriptor.value as TReturnDocument,
|
|
1200
1246
|
upsert: upsertDescriptor?.value === true,
|
|
@@ -1204,6 +1250,7 @@ const normalizeAtomicFindOneAndUpdateOptions = <
|
|
|
1204
1250
|
...(sessionDescriptor?.value !== undefined
|
|
1205
1251
|
? { session: sessionDescriptor.value as TSmartdataOrdinarySession }
|
|
1206
1252
|
: {}),
|
|
1253
|
+
...(timeoutMS !== undefined ? { timeoutMS } : {}),
|
|
1207
1254
|
};
|
|
1208
1255
|
};
|
|
1209
1256
|
|
|
@@ -1212,6 +1259,7 @@ const normalizeAtomicFindOneAndReplaceOptions = (
|
|
|
1212
1259
|
): {
|
|
1213
1260
|
returnDocument: TSmartdataAtomicReturnDocument;
|
|
1214
1261
|
session?: TSmartdataOrdinarySession;
|
|
1262
|
+
timeoutMS?: number;
|
|
1215
1263
|
} => {
|
|
1216
1264
|
if (optionsArg === undefined) {
|
|
1217
1265
|
return { returnDocument: 'after' };
|
|
@@ -1227,7 +1275,7 @@ const normalizeAtomicFindOneAndReplaceOptions = (
|
|
|
1227
1275
|
'Atomic find-one-and-replace options must be an inert plain object.',
|
|
1228
1276
|
);
|
|
1229
1277
|
}
|
|
1230
|
-
const allowedKeys = new Set(['returnDocument', 'session']);
|
|
1278
|
+
const allowedKeys = new Set(['returnDocument', 'session', 'timeoutMS']);
|
|
1231
1279
|
for (const key of Reflect.ownKeys(optionsArg)) {
|
|
1232
1280
|
if (typeof key !== 'string' || !allowedKeys.has(key)) {
|
|
1233
1281
|
throw new SmartdataPersistenceError(
|
|
@@ -1258,9 +1306,15 @@ const normalizeAtomicFindOneAndReplaceOptions = (
|
|
|
1258
1306
|
const session = Object.getOwnPropertyDescriptor(optionsArg, 'session')?.value as
|
|
1259
1307
|
| TSmartdataOrdinarySession
|
|
1260
1308
|
| undefined;
|
|
1309
|
+
const timeoutMS = requireBoundedInteger(
|
|
1310
|
+
Object.getOwnPropertyDescriptor(optionsArg, 'timeoutMS')?.value,
|
|
1311
|
+
'Atomic find-one-and-replace timeoutMS',
|
|
1312
|
+
120_000,
|
|
1313
|
+
);
|
|
1261
1314
|
return {
|
|
1262
1315
|
returnDocument: returnDocument ?? 'after',
|
|
1263
1316
|
...(session !== undefined ? { session } : {}),
|
|
1317
|
+
...(timeoutMS !== undefined ? { timeoutMS } : {}),
|
|
1264
1318
|
};
|
|
1265
1319
|
};
|
|
1266
1320
|
|
|
@@ -1281,7 +1335,7 @@ const normalizeAtomicExpressionUpdateOptions = (
|
|
|
1281
1335
|
'Atomic update options used with $expr must be an inert ordinary object.',
|
|
1282
1336
|
);
|
|
1283
1337
|
}
|
|
1284
|
-
const allowedKeys = new Set(['upsert', 'session']);
|
|
1338
|
+
const allowedKeys = new Set(['upsert', 'session', 'timeoutMS']);
|
|
1285
1339
|
const normalized: ISmartdataAtomicUpdateOptions = {};
|
|
1286
1340
|
for (const key of Reflect.ownKeys(optionsArg)) {
|
|
1287
1341
|
if (typeof key !== 'string' || !allowedKeys.has(key)) {
|
|
@@ -1314,6 +1368,10 @@ const normalizeAtomicExpressionUpdateOptions = (
|
|
|
1314
1368
|
if (descriptor.value !== undefined) {
|
|
1315
1369
|
normalized.upsert = descriptor.value;
|
|
1316
1370
|
}
|
|
1371
|
+
} else if (key === 'timeoutMS') {
|
|
1372
|
+
if (descriptor.value !== undefined) {
|
|
1373
|
+
normalized.timeoutMS = descriptor.value as number;
|
|
1374
|
+
}
|
|
1317
1375
|
} else if (descriptor.value !== undefined) {
|
|
1318
1376
|
normalized.session = descriptor.value as TSmartdataOrdinarySession;
|
|
1319
1377
|
}
|
|
@@ -3947,7 +4005,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
3947
4005
|
public static async insert<T extends SmartDataDbDoc<any, any>>(
|
|
3948
4006
|
this: plugins.tsclass.typeFest.Class<T>,
|
|
3949
4007
|
documentArg: T,
|
|
3950
|
-
opts?: {
|
|
4008
|
+
opts?: {
|
|
4009
|
+
session?: TSmartdataOrdinarySession;
|
|
4010
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
4011
|
+
timeoutMS?: number;
|
|
4012
|
+
},
|
|
3951
4013
|
): Promise<plugins.mongodb.InsertOneResult<{ _id: TSmartdataPrimaryId<T> }>> {
|
|
3952
4014
|
if ((this as any)[exactPersistencePolicySymbol]) {
|
|
3953
4015
|
throw new SmartdataPersistenceError(
|
|
@@ -3967,6 +4029,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
3967
4029
|
'Model insert requires a newly constructed document.',
|
|
3968
4030
|
);
|
|
3969
4031
|
}
|
|
4032
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'Model insert timeoutMS', 120_000);
|
|
3970
4033
|
assertUsableIdentityValues(
|
|
3971
4034
|
documentArg as unknown as Record<string, unknown>,
|
|
3972
4035
|
(this.prototype as { uniqueIndexes?: string[] }).uniqueIndexes || [],
|
|
@@ -3980,7 +4043,10 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
3980
4043
|
documentArg._updatedAt = now;
|
|
3981
4044
|
}
|
|
3982
4045
|
const collection: SmartdataCollection<T> = (this as any).collection;
|
|
3983
|
-
const result = await collection.insert(documentArg as any,
|
|
4046
|
+
const result = await collection.insert(documentArg as any, {
|
|
4047
|
+
session: opts?.session,
|
|
4048
|
+
timeoutMS,
|
|
4049
|
+
});
|
|
3984
4050
|
if (!isOrdinarySessionInTransaction(opts?.session)) {
|
|
3985
4051
|
documentArg.creationStatus = 'db';
|
|
3986
4052
|
}
|
|
@@ -3998,7 +4064,12 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
3998
4064
|
public static async insertMany<T extends SmartDataDbDoc<any, any>>(
|
|
3999
4065
|
this: plugins.tsclass.typeFest.Class<T>,
|
|
4000
4066
|
documentsArg: T[],
|
|
4001
|
-
opts?: {
|
|
4067
|
+
opts?: {
|
|
4068
|
+
session?: TSmartdataOrdinarySession;
|
|
4069
|
+
ordered?: boolean;
|
|
4070
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
4071
|
+
timeoutMS?: number;
|
|
4072
|
+
},
|
|
4002
4073
|
): Promise<plugins.mongodb.InsertManyResult<{ _id: TSmartdataPrimaryId<T> }>> {
|
|
4003
4074
|
if ((this as any)[exactPersistencePolicySymbol]) {
|
|
4004
4075
|
throw new SmartdataPersistenceError(
|
|
@@ -4021,6 +4092,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4021
4092
|
'Model insertMany ordered must be a boolean.',
|
|
4022
4093
|
);
|
|
4023
4094
|
}
|
|
4095
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'Model insertMany timeoutMS', 120_000);
|
|
4024
4096
|
const seenDocuments = new Set<T>();
|
|
4025
4097
|
for (const documentArg of documentsArg) {
|
|
4026
4098
|
if (!(documentArg instanceof this)) {
|
|
@@ -4073,7 +4145,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4073
4145
|
}
|
|
4074
4146
|
};
|
|
4075
4147
|
try {
|
|
4076
|
-
const result = await collection.insertMany(documentsArg as any,
|
|
4148
|
+
const result = await collection.insertMany(documentsArg as any, {
|
|
4149
|
+
session: opts?.session,
|
|
4150
|
+
ordered: opts?.ordered,
|
|
4151
|
+
timeoutMS,
|
|
4152
|
+
});
|
|
4077
4153
|
markInsertedDocuments(
|
|
4078
4154
|
result.insertedIds as unknown as Record<number, unknown>,
|
|
4079
4155
|
);
|
|
@@ -4193,6 +4269,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4193
4269
|
const normalizedOptions = '$expr' in normalizedFilter
|
|
4194
4270
|
? normalizeAtomicExpressionUpdateOptions(opts)
|
|
4195
4271
|
: opts;
|
|
4272
|
+
const timeoutMS = requireBoundedInteger(
|
|
4273
|
+
normalizedOptions?.timeoutMS,
|
|
4274
|
+
'Atomic update timeoutMS',
|
|
4275
|
+
120_000,
|
|
4276
|
+
);
|
|
4196
4277
|
if (normalizedOptions?.upsert === true && '$expr' in normalizedFilter) {
|
|
4197
4278
|
throw new SmartdataPersistenceError(
|
|
4198
4279
|
'invalid_argument',
|
|
@@ -4242,7 +4323,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4242
4323
|
collection,
|
|
4243
4324
|
mapIdentityFilterToDocumentId(normalizedFilter, identityDocumentIdField),
|
|
4244
4325
|
normalizedUpdate,
|
|
4245
|
-
|
|
4326
|
+
{
|
|
4327
|
+
upsert: normalizedOptions?.upsert,
|
|
4328
|
+
session: normalizedOptions?.session,
|
|
4329
|
+
timeoutMS,
|
|
4330
|
+
},
|
|
4246
4331
|
);
|
|
4247
4332
|
return {
|
|
4248
4333
|
acknowledged: result.acknowledged,
|
|
@@ -4346,6 +4431,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4346
4431
|
upsert: normalizedOptions.upsert,
|
|
4347
4432
|
...(normalizedSort ? { sort: normalizedSort as Record<string, 1 | -1> } : {}),
|
|
4348
4433
|
...(normalizedOptions.session ? { session: normalizedOptions.session } : {}),
|
|
4434
|
+
timeoutMS: normalizedOptions.timeoutMS,
|
|
4349
4435
|
},
|
|
4350
4436
|
);
|
|
4351
4437
|
if (result.document === null) {
|
|
@@ -4473,6 +4559,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4473
4559
|
{
|
|
4474
4560
|
returnDocument: normalizedOptions.returnDocument,
|
|
4475
4561
|
...(normalizedOptions.session ? { session: normalizedOptions.session } : {}),
|
|
4562
|
+
timeoutMS: normalizedOptions.timeoutMS,
|
|
4476
4563
|
},
|
|
4477
4564
|
);
|
|
4478
4565
|
if (result.status === 'not_matched') {
|
|
@@ -4550,7 +4637,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4550
4637
|
public static async atomicDeleteMany<T>(
|
|
4551
4638
|
this: plugins.tsclass.typeFest.Class<T>,
|
|
4552
4639
|
filterArg: TSmartdataAtomicFilter<T>,
|
|
4553
|
-
opts?:
|
|
4640
|
+
opts?: ISmartdataAtomicDeleteManyOptions,
|
|
4554
4641
|
): Promise<ISmartdataAtomicDeleteResult> {
|
|
4555
4642
|
if ((this as any)[exactPersistencePolicySymbol]) {
|
|
4556
4643
|
throw new SmartdataPersistenceError(
|
|
@@ -4582,7 +4669,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4582
4669
|
normalizedFilter,
|
|
4583
4670
|
(this as any).getIdentityDocumentIdField() as string | undefined,
|
|
4584
4671
|
),
|
|
4585
|
-
{
|
|
4672
|
+
{
|
|
4673
|
+
session: opts?.session,
|
|
4674
|
+
timeoutMS: requireBoundedInteger(opts?.timeoutMS, 'Atomic delete-many timeoutMS', 120_000),
|
|
4675
|
+
signal: requireOperationSignal(opts?.signal, 'Atomic delete-many signal'),
|
|
4676
|
+
},
|
|
4586
4677
|
);
|
|
4587
4678
|
return {
|
|
4588
4679
|
acknowledged: result.acknowledged,
|
|
@@ -4622,6 +4713,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4622
4713
|
'Atomic update-many does not support $setOnInsert.',
|
|
4623
4714
|
);
|
|
4624
4715
|
}
|
|
4716
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'Atomic update-many timeoutMS', 120_000);
|
|
4625
4717
|
const declaredRoots = (this as any).getDeclaredPersistedRoots() as Set<string>;
|
|
4626
4718
|
const declaredAtomicPaths = (this as any).getDeclaredAtomicPaths() as Set<string>;
|
|
4627
4719
|
const uniqueRoots = (this as any).getDeclaredUniqueRoots() as Set<string>;
|
|
@@ -4660,7 +4752,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
4660
4752
|
(this as any).getIdentityDocumentIdField() as string | undefined,
|
|
4661
4753
|
),
|
|
4662
4754
|
normalizedUpdate,
|
|
4663
|
-
opts,
|
|
4755
|
+
{ session: opts?.session, timeoutMS },
|
|
4664
4756
|
);
|
|
4665
4757
|
return {
|
|
4666
4758
|
acknowledged: result.acknowledged,
|
|
@@ -5096,12 +5188,23 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5096
5188
|
public static async getInstances<T>(
|
|
5097
5189
|
this: plugins.tsclass.typeFest.Class<T>,
|
|
5098
5190
|
filterArg: MongoFilter<T>,
|
|
5099
|
-
opts?: {
|
|
5191
|
+
opts?: {
|
|
5192
|
+
session?: TSmartdataOrdinarySession;
|
|
5193
|
+
/**
|
|
5194
|
+
* Client-side deadline for the read (1..120000 ms), from model
|
|
5195
|
+
* initialization to the cursor's last reply. A timed-out `getMore` is
|
|
5196
|
+
* followed by the driver's `killCursors` on a fresh deadline of the same
|
|
5197
|
+
* length, so a read that needs more than one batch settles within about
|
|
5198
|
+
* twice `timeoutMS` against a stalled database.
|
|
5199
|
+
*/
|
|
5200
|
+
timeoutMS?: number;
|
|
5201
|
+
}
|
|
5100
5202
|
): Promise<T[]> {
|
|
5203
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'timeoutMS', 120_000);
|
|
5101
5204
|
// Pass session through to findAll for transactional queries
|
|
5102
5205
|
const foundDocs = await (this as any).collection.findAll(
|
|
5103
5206
|
(this as any).normalizeReadFilter(filterArg),
|
|
5104
|
-
{ session: opts?.session },
|
|
5207
|
+
{ session: opts?.session, timeoutMS },
|
|
5105
5208
|
);
|
|
5106
5209
|
const returnArray: T[] = [];
|
|
5107
5210
|
for (const foundDoc of foundDocs) {
|
|
@@ -5135,6 +5238,14 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5135
5238
|
/** Also count all filter matches (extra query). */
|
|
5136
5239
|
withTotal?: boolean;
|
|
5137
5240
|
session?: TSmartdataOrdinarySession;
|
|
5241
|
+
/**
|
|
5242
|
+
* Client-side deadline for the page and its optional count together
|
|
5243
|
+
* (1..120000 ms). A page that needs more than one batch can settle
|
|
5244
|
+
* within about twice `timeoutMS` against a stalled database: the
|
|
5245
|
+
* driver's `killCursors` after a timed-out `getMore` gets a fresh
|
|
5246
|
+
* deadline of the same length.
|
|
5247
|
+
*/
|
|
5248
|
+
timeoutMS?: number;
|
|
5138
5249
|
},
|
|
5139
5250
|
): Promise<{
|
|
5140
5251
|
documents: T[];
|
|
@@ -5149,6 +5260,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5149
5260
|
? optionsArg.limit!
|
|
5150
5261
|
: 100;
|
|
5151
5262
|
const limit = Math.min(requestedLimit, 1000);
|
|
5263
|
+
const timeoutMS = requireBoundedInteger(optionsArg.timeoutMS, 'timeoutMS', 120_000);
|
|
5152
5264
|
const baseSelector = (this as any).normalizeReadFilter(optionsArg.filter || {});
|
|
5153
5265
|
|
|
5154
5266
|
let selector: any = baseSelector;
|
|
@@ -5172,10 +5284,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5172
5284
|
ordinaryWrite: false,
|
|
5173
5285
|
prepared: collection.isInitializedForCurrentDatabase(),
|
|
5174
5286
|
collectionName: collection.collectionName,
|
|
5175
|
-
|
|
5176
|
-
|
|
5287
|
+
timeoutMS,
|
|
5288
|
+
}, async (rawSessionArg, deadlineArg) => {
|
|
5289
|
+
await deadlineArg.join(collection.init());
|
|
5177
5290
|
const rawCursor = collection.mongoDbCollection
|
|
5178
|
-
.find(selector, { session: rawSessionArg })
|
|
5291
|
+
.find(selector, { session: rawSessionArg, ...deadlineArg.cursorOptions() })
|
|
5179
5292
|
.sort({ [optionsArg.sortField]: sortDirection, [uniqueField]: sortDirection })
|
|
5180
5293
|
.limit(limit + 1);
|
|
5181
5294
|
return runCursorOperation(rawCursor, async (cursorArg) => {
|
|
@@ -5189,6 +5302,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5189
5302
|
const total = optionsArg.withTotal
|
|
5190
5303
|
? await collection.mongoDbCollection.countDocuments(baseSelector, {
|
|
5191
5304
|
session: rawSessionArg,
|
|
5305
|
+
...deadlineArg.commandOptions(),
|
|
5192
5306
|
})
|
|
5193
5307
|
: undefined;
|
|
5194
5308
|
return {
|
|
@@ -5203,7 +5317,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5203
5317
|
: {}),
|
|
5204
5318
|
...(total !== undefined ? { total } : {}),
|
|
5205
5319
|
};
|
|
5206
|
-
});
|
|
5320
|
+
}, deadlineArg.signal);
|
|
5207
5321
|
});
|
|
5208
5322
|
}
|
|
5209
5323
|
|
|
@@ -5234,6 +5348,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5234
5348
|
'maxTimeMS',
|
|
5235
5349
|
120_000,
|
|
5236
5350
|
),
|
|
5351
|
+
timeoutMS: requireBoundedInteger(opts?.timeoutMS, 'timeoutMS', 120_000),
|
|
5237
5352
|
session: opts?.session,
|
|
5238
5353
|
},
|
|
5239
5354
|
);
|
|
@@ -5250,6 +5365,8 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5250
5365
|
filterArg: MongoFilter<T>,
|
|
5251
5366
|
opts?: {
|
|
5252
5367
|
maxTimeMS?: number;
|
|
5368
|
+
/** Client-side deadline for the call's database work (1..120000 ms), including model initialization, server selection and pool waits. */
|
|
5369
|
+
timeoutMS?: number;
|
|
5253
5370
|
session?: TSmartdataOrdinarySession;
|
|
5254
5371
|
},
|
|
5255
5372
|
): Promise<boolean> {
|
|
@@ -5262,6 +5379,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5262
5379
|
'maxTimeMS',
|
|
5263
5380
|
120_000,
|
|
5264
5381
|
),
|
|
5382
|
+
timeoutMS: requireBoundedInteger(opts?.timeoutMS, 'timeoutMS', 120_000),
|
|
5265
5383
|
session: opts?.session,
|
|
5266
5384
|
},
|
|
5267
5385
|
);
|
|
@@ -5406,10 +5524,9 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5406
5524
|
'Offset pages require sort, limit and an integer skip from 0 through 2147483647.',
|
|
5407
5525
|
);
|
|
5408
5526
|
}
|
|
5409
|
-
const timeoutMS = requireBoundedInteger(opts?.timeoutMS
|
|
5527
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'timeoutMS', 120_000);
|
|
5410
5528
|
const maxTimeMS = requireBoundedInteger(opts?.maxTimeMS, 'maxTimeMS', 120_000);
|
|
5411
5529
|
const filter = (this as any).normalizeReadFilter(filterArg);
|
|
5412
|
-
opts.signal?.throwIfAborted();
|
|
5413
5530
|
const collection: SmartdataCollection<T> = (this as any).collection;
|
|
5414
5531
|
if (!collection.isInitializedForCurrentDatabase()) {
|
|
5415
5532
|
throw new SmartdataPersistenceError(
|
|
@@ -5420,18 +5537,20 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5420
5537
|
return runWithOrdinarySmartdataSession(opts.session, collection.smartdataDb, {
|
|
5421
5538
|
ordinaryWrite: false,
|
|
5422
5539
|
prepared: true,
|
|
5423
|
-
|
|
5424
|
-
|
|
5540
|
+
timeoutMS,
|
|
5541
|
+
defaultTimeoutMS: 5_000,
|
|
5542
|
+
signal: opts.signal,
|
|
5543
|
+
}, async (rawSessionArg, deadlineArg) => {
|
|
5425
5544
|
const rawCursor = collection.mongoDbCollection.find(filter, {
|
|
5426
|
-
projection, sort, hint, skip, limit, maxTimeMS,
|
|
5427
|
-
|
|
5545
|
+
projection, sort, hint, skip, limit, maxTimeMS,
|
|
5546
|
+
...deadlineArg.cursorOptions(), session: rawSessionArg,
|
|
5428
5547
|
});
|
|
5429
5548
|
return runCursorOperation(rawCursor, async (cursorArg) => {
|
|
5430
5549
|
const documents = await cursorArg.toArray();
|
|
5431
5550
|
return documents.map((documentArg) =>
|
|
5432
5551
|
(this as any).createInstanceFromMongoDbNativeDoc(documentArg) as T,
|
|
5433
5552
|
);
|
|
5434
|
-
},
|
|
5553
|
+
}, deadlineArg.signal);
|
|
5435
5554
|
});
|
|
5436
5555
|
}
|
|
5437
5556
|
|
|
@@ -5778,7 +5897,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5778
5897
|
* handle from `db.createSession()` — leased for the one write, like every
|
|
5779
5898
|
* other model API — or a raw driver session.
|
|
5780
5899
|
*/
|
|
5781
|
-
public async save(opts?: {
|
|
5900
|
+
public async save(opts?: {
|
|
5901
|
+
session?: TSmartdataOrdinarySession;
|
|
5902
|
+
/** Client-side deadline for the write (1..120000 ms); `beforeSave()` and `afterSave()` run outside it. */
|
|
5903
|
+
timeoutMS?: number;
|
|
5904
|
+
}) {
|
|
5782
5905
|
if (getOrdinaryPersistencePolicy(this.constructor)) {
|
|
5783
5906
|
throw new SmartdataPersistenceError('unsupported_operation',
|
|
5784
5907
|
'Validated ordinary models use insert() or transactional postimage updates.');
|
|
@@ -5792,6 +5915,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5792
5915
|
}
|
|
5793
5916
|
throw new Error('save() is unavailable for exact-persistence models.');
|
|
5794
5917
|
}
|
|
5918
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'Model save timeoutMS', 120_000);
|
|
5795
5919
|
// allow hook before saving
|
|
5796
5920
|
if (typeof (this as any).beforeSave === 'function') {
|
|
5797
5921
|
await (this as any).beforeSave();
|
|
@@ -5809,10 +5933,10 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5809
5933
|
// perform insert or update
|
|
5810
5934
|
switch (this.creationStatus) {
|
|
5811
5935
|
case 'db':
|
|
5812
|
-
dbResult = await this.getCollectionSafe().update(self, { session: opts?.session });
|
|
5936
|
+
dbResult = await this.getCollectionSafe().update(self, { session: opts?.session, timeoutMS });
|
|
5813
5937
|
break;
|
|
5814
5938
|
case 'new':
|
|
5815
|
-
dbResult = await this.getCollectionSafe().insert(self, { session: opts?.session });
|
|
5939
|
+
dbResult = await this.getCollectionSafe().insert(self, { session: opts?.session, timeoutMS });
|
|
5816
5940
|
this.creationStatus = 'db';
|
|
5817
5941
|
break;
|
|
5818
5942
|
default:
|
|
@@ -5959,7 +6083,7 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5959
6083
|
$set: setObject,
|
|
5960
6084
|
...(Object.keys(unsetObject).length > 0 ? { $unset: unsetObject } : {}),
|
|
5961
6085
|
},
|
|
5962
|
-
{ session: options.session },
|
|
6086
|
+
{ session: options.session, timeoutMS: options.timeoutMS },
|
|
5963
6087
|
);
|
|
5964
6088
|
if (result.matchedCount === 0) {
|
|
5965
6089
|
// Nothing was written, so the instance keeps the update timestamp the
|
|
@@ -5986,7 +6110,11 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5986
6110
|
* `session` takes the handle from `db.createSession()` — leased for the one
|
|
5987
6111
|
* write, like every other model API — or a raw driver session.
|
|
5988
6112
|
*/
|
|
5989
|
-
public async delete(opts?: {
|
|
6113
|
+
public async delete(opts?: {
|
|
6114
|
+
session?: TSmartdataOrdinarySession;
|
|
6115
|
+
/** Client-side deadline for the write (1..120000 ms); `beforeDelete()` and `afterDelete()` run outside it. */
|
|
6116
|
+
timeoutMS?: number;
|
|
6117
|
+
}) {
|
|
5990
6118
|
const exactPersistencePolicy = (this.constructor as any)[
|
|
5991
6119
|
exactPersistencePolicySymbol
|
|
5992
6120
|
] as { forbiddenDelete?: () => Promise<never> } | undefined;
|
|
@@ -5996,12 +6124,13 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5996
6124
|
}
|
|
5997
6125
|
throw new Error('delete() is forbidden for exact-persistence models.');
|
|
5998
6126
|
}
|
|
6127
|
+
const timeoutMS = requireBoundedInteger(opts?.timeoutMS, 'Model delete timeoutMS', 120_000);
|
|
5999
6128
|
// allow hook before deleting
|
|
6000
6129
|
if (typeof (this as any).beforeDelete === 'function') {
|
|
6001
6130
|
await (this as any).beforeDelete();
|
|
6002
6131
|
}
|
|
6003
6132
|
// perform deletion
|
|
6004
|
-
const result = await this.getCollectionSafe().delete(this, { session: opts?.session });
|
|
6133
|
+
const result = await this.getCollectionSafe().delete(this, { session: opts?.session, timeoutMS });
|
|
6005
6134
|
// allow hook after delete
|
|
6006
6135
|
if (typeof (this as any).afterDelete === 'function') {
|
|
6007
6136
|
await (this as any).afterDelete();
|