@lossless.org/client 0.1.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/.smartconfig.json +37 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.losslessorgclient.d.ts +32 -0
- package/dist_ts/classes.losslessorgclient.js +103 -0
- package/dist_ts/core/classes.error.d.ts +16 -0
- package/dist_ts/core/classes.error.js +29 -0
- package/dist_ts/core/classes.operation.d.ts +17 -0
- package/dist_ts/core/classes.operation.js +70 -0
- package/dist_ts/core/interfaces.d.ts +18 -0
- package/dist_ts/core/interfaces.js +2 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +3 -0
- package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
- package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
- package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
- package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
- package/dist_ts/nosqldb/classes.cached-document.js +112 -0
- package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
- package/dist_ts/nosqldb/classes.collection.js +1568 -0
- package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
- package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
- package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
- package/dist_ts/nosqldb/classes.connection.js +23 -0
- package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
- package/dist_ts/nosqldb/classes.convenience.js +5 -0
- package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
- package/dist_ts/nosqldb/classes.cursor.js +82 -0
- package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
- package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
- package/dist_ts/nosqldb/classes.db.d.ts +98 -0
- package/dist_ts/nosqldb/classes.db.js +434 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
- package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
- package/dist_ts/nosqldb/classes.doc.js +2976 -0
- package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
- package/dist_ts/nosqldb/classes.easystore.js +199 -0
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
- package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
- package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
- package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
- package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
- package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
- package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
- package/dist_ts/nosqldb/classes.persistence.js +34 -0
- package/dist_ts/nosqldb/classes.session.d.ts +28 -0
- package/dist_ts/nosqldb/classes.session.js +246 -0
- package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
- package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
- package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
- package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
- package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
- package/dist_ts/nosqldb/classes.watcher.js +98 -0
- package/dist_ts/nosqldb/index.d.ts +27 -0
- package/dist_ts/nosqldb/index.js +18 -0
- package/dist_ts/nosqldb/logging.d.ts +2 -0
- package/dist_ts/nosqldb/logging.js +3 -0
- package/dist_ts/nosqldb/plugins.d.ts +17 -0
- package/dist_ts/nosqldb/plugins.js +20 -0
- package/dist_ts/nosqldb/shim.d.ts +1 -0
- package/dist_ts/nosqldb/shim.js +8 -0
- package/dist_ts/nosqldb/testsupport.d.ts +3 -0
- package/dist_ts/nosqldb/testsupport.js +3 -0
- package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
- package/dist_ts/objectstorage/classes.bucket.js +939 -0
- package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
- package/dist_ts/objectstorage/classes.connection.js +27 -0
- package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
- package/dist_ts/objectstorage/classes.directory.js +335 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
- package/dist_ts/objectstorage/classes.file.d.ts +91 -0
- package/dist_ts/objectstorage/classes.file.js +255 -0
- package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
- package/dist_ts/objectstorage/classes.listcursor.js +67 -0
- package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
- package/dist_ts/objectstorage/classes.metadata.js +113 -0
- package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
- package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
- package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
- package/dist_ts/objectstorage/classes.trash.js +22 -0
- package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
- package/dist_ts/objectstorage/classes.watcher.js +249 -0
- package/dist_ts/objectstorage/helpers.d.ts +25 -0
- package/dist_ts/objectstorage/helpers.js +215 -0
- package/dist_ts/objectstorage/index.d.ts +13 -0
- package/dist_ts/objectstorage/index.js +13 -0
- package/dist_ts/objectstorage/interfaces.d.ts +276 -0
- package/dist_ts/objectstorage/interfaces.js +2 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
- package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
- package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
- package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
- package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
- package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
- package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
- package/dist_ts/objectstorage/plugins.d.ts +17 -0
- package/dist_ts/objectstorage/plugins.js +23 -0
- package/dist_ts/plugins.d.ts +4 -0
- package/dist_ts/plugins.js +5 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
- package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
- package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
- package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
- package/dist_ts/sqldb/classes.sqltable.js +70 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
- package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
- package/dist_ts/sqldb/clickhouse/index.js +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
- package/dist_ts/sqldb/index.d.ts +6 -0
- package/dist_ts/sqldb/index.js +6 -0
- package/dist_ts/sqldb/interfaces.d.ts +53 -0
- package/dist_ts/sqldb/interfaces.js +19 -0
- package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
- package/dist_ts/sqldb/internal.sqlpool.js +214 -0
- package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
- package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
- package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
- package/dist_ts/sqldb/plugins.mariadb.js +5 -0
- package/docs/source/smartbucket/license.md +19 -0
- package/docs/source/smartclickhouse/license.md +19 -0
- package/license.md +21 -0
- package/package.json +101 -0
- package/readme.md +157 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.losslessorgclient.ts +104 -0
- package/ts/core/classes.error.ts +31 -0
- package/ts/core/classes.operation.ts +60 -0
- package/ts/core/interfaces.ts +24 -0
- package/ts/index.ts +4 -0
- package/ts/nosqldb/classes.atomicdelete.ts +81 -0
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
- package/ts/nosqldb/classes.atomicupdate.ts +99 -0
- package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
- package/ts/nosqldb/classes.bsonassertion.ts +25 -0
- package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
- package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
- package/ts/nosqldb/classes.cached-document.ts +67 -0
- package/ts/nosqldb/classes.collection.ts +2399 -0
- package/ts/nosqldb/classes.collectionfactory.ts +87 -0
- package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
- package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
- package/ts/nosqldb/classes.collectiontopology.ts +645 -0
- package/ts/nosqldb/classes.connection.ts +31 -0
- package/ts/nosqldb/classes.convenience.ts +5 -0
- package/ts/nosqldb/classes.cursor.ts +88 -0
- package/ts/nosqldb/classes.cursoroperation.ts +38 -0
- package/ts/nosqldb/classes.db.ts +637 -0
- package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
- package/ts/nosqldb/classes.doc.ts +4928 -0
- package/ts/nosqldb/classes.easystore.ts +154 -0
- package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
- package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
- package/ts/nosqldb/classes.mongoadministration.ts +867 -0
- package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
- package/ts/nosqldb/classes.operationbudget.ts +75 -0
- package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
- package/ts/nosqldb/classes.persistence.ts +62 -0
- package/ts/nosqldb/classes.session.ts +389 -0
- package/ts/nosqldb/classes.storedinspection.ts +151 -0
- package/ts/nosqldb/classes.testdatabase.ts +272 -0
- package/ts/nosqldb/classes.watcher.ts +96 -0
- package/ts/nosqldb/index.ts +51 -0
- package/ts/nosqldb/logging.ts +3 -0
- package/ts/nosqldb/plugins.ts +37 -0
- package/ts/nosqldb/shim.ts +6 -0
- package/ts/nosqldb/testsupport.ts +13 -0
- package/ts/objectstorage/classes.bucket.ts +1114 -0
- package/ts/objectstorage/classes.connection.ts +36 -0
- package/ts/objectstorage/classes.directory.ts +425 -0
- package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
- package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
- package/ts/objectstorage/classes.file.ts +303 -0
- package/ts/objectstorage/classes.listcursor.ts +89 -0
- package/ts/objectstorage/classes.metadata.ts +134 -0
- package/ts/objectstorage/classes.smartbucket.ts +445 -0
- package/ts/objectstorage/classes.trash.ts +30 -0
- package/ts/objectstorage/classes.watcher.ts +289 -0
- package/ts/objectstorage/helpers.ts +254 -0
- package/ts/objectstorage/index.ts +13 -0
- package/ts/objectstorage/interfaces.ts +389 -0
- package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
- package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
- package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
- package/ts/objectstorage/internal.multipart.planner.ts +90 -0
- package/ts/objectstorage/internal.multipart.stream.ts +606 -0
- package/ts/objectstorage/internal.multipart.types.ts +106 -0
- package/ts/objectstorage/plugins.ts +35 -0
- package/ts/plugins.ts +4 -0
- package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
- package/ts/sqldb/classes.sqlconnection.ts +350 -0
- package/ts/sqldb/classes.sqltable.ts +70 -0
- package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
- package/ts/sqldb/clickhouse/index.ts +16 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
- package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
- package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
- package/ts/sqldb/index.ts +6 -0
- package/ts/sqldb/interfaces.ts +61 -0
- package/ts/sqldb/internal.sqlpool.ts +179 -0
- package/ts/sqldb/plugins.clickhouse.ts +4 -0
- package/ts/sqldb/plugins.mariadb.ts +4 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
|
|
3
|
+
import { SmartdataCollection } from './classes.collection.js';
|
|
4
|
+
import { EasyStore } from './classes.easystore.js';
|
|
5
|
+
import { SmartdataPersistenceError } from './classes.persistence.js';
|
|
6
|
+
import { SmartdataMongoAdministration } from './classes.mongoadministration.js';
|
|
7
|
+
import {
|
|
8
|
+
createSmartdataSession,
|
|
9
|
+
invalidateSmartdataSessions,
|
|
10
|
+
SmartdataSession,
|
|
11
|
+
unwrapSmartdataSessionInvalidationErrors,
|
|
12
|
+
} from './classes.session.js';
|
|
13
|
+
import { collectionTopologyDbInspectionSymbol } from './classes.collectiontopology.js';
|
|
14
|
+
import {
|
|
15
|
+
inspectSmartdataNamespace,
|
|
16
|
+
type ISmartdataNamespaceInspectionOptions,
|
|
17
|
+
type ISmartdataNamespaceInspection,
|
|
18
|
+
} from './classes.namespaceinspection.js';
|
|
19
|
+
|
|
20
|
+
export { SmartdataSession } from './classes.session.js';
|
|
21
|
+
export type { TSmartdataOrdinarySession } from './classes.session.js';
|
|
22
|
+
|
|
23
|
+
import { logger } from './logging.js';
|
|
24
|
+
import { assertDataOptions, SmartdataOperationBudget } from './classes.operationbudget.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* interface - indicates the connection status of the db
|
|
28
|
+
*/
|
|
29
|
+
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
|
30
|
+
|
|
31
|
+
export interface ISmartdataReadinessOptions {
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ISmartdataInitOptions {
|
|
37
|
+
/** Bounds connection setup; cleanup is always joined before the call settles. */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
signal?: AbortSignal;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ISmartdataCloseOptions {
|
|
43
|
+
/** Total deadline for removal, including preceding session cleanup (1..120000 ms). */
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
dropDatabase?: {
|
|
46
|
+
expectedDatabaseName: string;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type TSmartdataReadinessFailureReason =
|
|
51
|
+
| 'not_initialized'
|
|
52
|
+
| 'connecting'
|
|
53
|
+
| 'connection_failed'
|
|
54
|
+
| 'closing'
|
|
55
|
+
| 'closed'
|
|
56
|
+
| 'close_failed'
|
|
57
|
+
| 'aborted'
|
|
58
|
+
| 'timeout'
|
|
59
|
+
| 'unavailable';
|
|
60
|
+
|
|
61
|
+
export type TSmartdataReadinessResult =
|
|
62
|
+
| {
|
|
63
|
+
ready: true;
|
|
64
|
+
status: 'ready';
|
|
65
|
+
durationMs: number;
|
|
66
|
+
}
|
|
67
|
+
| {
|
|
68
|
+
ready: false;
|
|
69
|
+
status: 'unavailable';
|
|
70
|
+
reason: TSmartdataReadinessFailureReason;
|
|
71
|
+
durationMs: number;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
type TSmartdataDbLifecycleState =
|
|
75
|
+
| 'initial'
|
|
76
|
+
| 'connecting'
|
|
77
|
+
| 'connected'
|
|
78
|
+
| 'connection_failed'
|
|
79
|
+
| 'closing'
|
|
80
|
+
| 'closed'
|
|
81
|
+
| 'close_failed';
|
|
82
|
+
|
|
83
|
+
type TSmartdataDbLifecycleOperation = 'init' | 'close';
|
|
84
|
+
|
|
85
|
+
const readinessDefaultTimeoutMs = 2_000;
|
|
86
|
+
const readinessMaximumTimeoutMs = 30_000;
|
|
87
|
+
|
|
88
|
+
const assertExactDataObject = (
|
|
89
|
+
valueArg: unknown,
|
|
90
|
+
expectedKeysArg: readonly string[],
|
|
91
|
+
descriptionArg: string,
|
|
92
|
+
allowEmptyArg = false,
|
|
93
|
+
): Record<string, unknown> => {
|
|
94
|
+
if (
|
|
95
|
+
valueArg === null ||
|
|
96
|
+
typeof valueArg !== 'object' ||
|
|
97
|
+
Array.isArray(valueArg) ||
|
|
98
|
+
Object.getPrototypeOf(valueArg) !== Object.prototype
|
|
99
|
+
) {
|
|
100
|
+
throw new SmartdataPersistenceError(
|
|
101
|
+
'invalid_argument',
|
|
102
|
+
`${descriptionArg} must be a plain object.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const keys = Reflect.ownKeys(valueArg);
|
|
106
|
+
if (
|
|
107
|
+
(!allowEmptyArg && keys.length !== expectedKeysArg.length) ||
|
|
108
|
+
(allowEmptyArg && keys.length !== 0 && keys.length !== expectedKeysArg.length) ||
|
|
109
|
+
keys.some(
|
|
110
|
+
(keyArg) =>
|
|
111
|
+
typeof keyArg !== 'string' || !expectedKeysArg.includes(keyArg),
|
|
112
|
+
)
|
|
113
|
+
) {
|
|
114
|
+
throw new SmartdataPersistenceError(
|
|
115
|
+
'invalid_argument',
|
|
116
|
+
`${descriptionArg} has an invalid shape.`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
for (const key of keys as string[]) {
|
|
120
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
|
|
121
|
+
if (!descriptor || !('value' in descriptor)) {
|
|
122
|
+
throw new SmartdataPersistenceError(
|
|
123
|
+
'invalid_argument',
|
|
124
|
+
`${descriptionArg} must contain data properties only.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return valueArg as Record<string, unknown>;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export class SmartdataDb {
|
|
132
|
+
smartdataOptions: plugins.tsclass.database.IMongoDescriptor;
|
|
133
|
+
mongoDbClient!: plugins.mongodb.MongoClient;
|
|
134
|
+
mongoDb!: plugins.mongodb.Db;
|
|
135
|
+
status: TConnectionStatus;
|
|
136
|
+
statusConnectedDeferred = plugins.smartpromise.defer();
|
|
137
|
+
smartdataCollectionMap = new plugins.lik.ObjectMap<SmartdataCollection<any>>();
|
|
138
|
+
private lifecycleState: TSmartdataDbLifecycleState = 'initial';
|
|
139
|
+
private lifecycleEpoch = 0;
|
|
140
|
+
private activeLifecycleOperation: TSmartdataDbLifecycleOperation | null = null;
|
|
141
|
+
private pendingClient?: plugins.mongodb.MongoClient;
|
|
142
|
+
|
|
143
|
+
constructor(smartdataOptions: plugins.tsclass.database.IMongoDescriptor) {
|
|
144
|
+
this.smartdataOptions = smartdataOptions;
|
|
145
|
+
this.status = 'initial';
|
|
146
|
+
void this.statusConnectedDeferred.promise.catch(() => {});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// easystore
|
|
150
|
+
public async createEasyStore<T = unknown>(nameIdArg: string): Promise<EasyStore<T>> {
|
|
151
|
+
const easyStore = new EasyStore<T>(nameIdArg, this);
|
|
152
|
+
return easyStore;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// basic connection stuff ----------------------------------------------
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* connects to the database that was specified during instance creation
|
|
159
|
+
*/
|
|
160
|
+
public async init(optionsArg: ISmartdataInitOptions = {}): Promise<void> {
|
|
161
|
+
this.assertLifecycleOperationCanBegin('init');
|
|
162
|
+
const options = assertDataOptions(optionsArg, ['timeoutMs', 'signal']);
|
|
163
|
+
const budget = Object.keys(options).length
|
|
164
|
+
? new SmartdataOperationBudget(options.timeoutMs ?? 30_000, options.signal) : undefined;
|
|
165
|
+
try { budget?.check(); } catch (errorArg) { budget?.close(); throw errorArg; }
|
|
166
|
+
this.beginLifecycleOperation('init');
|
|
167
|
+
this.transitionLifecycle('connecting');
|
|
168
|
+
let candidateClient: plugins.mongodb.MongoClient | undefined;
|
|
169
|
+
try {
|
|
170
|
+
try {
|
|
171
|
+
// Safely encode credentials to handle special characters
|
|
172
|
+
const encodedUser = this.smartdataOptions.mongoDbUser
|
|
173
|
+
? encodeURIComponent(this.smartdataOptions.mongoDbUser)
|
|
174
|
+
: '';
|
|
175
|
+
const encodedPass = this.smartdataOptions.mongoDbPass
|
|
176
|
+
? encodeURIComponent(this.smartdataOptions.mongoDbPass)
|
|
177
|
+
: '';
|
|
178
|
+
|
|
179
|
+
const finalConnectionUrl = this.smartdataOptions.mongoDbUrl
|
|
180
|
+
.replace('<USERNAME>', encodedUser)
|
|
181
|
+
.replace('<username>', encodedUser)
|
|
182
|
+
.replace('<USER>', encodedUser)
|
|
183
|
+
.replace('<user>', encodedUser)
|
|
184
|
+
.replace('<PASSWORD>', encodedPass)
|
|
185
|
+
.replace('<password>', encodedPass)
|
|
186
|
+
.replace('<DBNAME>', this.smartdataOptions.mongoDbName || '')
|
|
187
|
+
.replace('<dbname>', this.smartdataOptions.mongoDbName || '');
|
|
188
|
+
|
|
189
|
+
const descriptor = this.smartdataOptions as plugins.tsclass.database.IMongoDescriptor &
|
|
190
|
+
Pick<plugins.mongodb.MongoClientOptions, 'maxPoolSize' | 'maxIdleTimeMS' |
|
|
191
|
+
'serverSelectionTimeoutMS' | 'socketTimeoutMS'>;
|
|
192
|
+
const clientOptions: plugins.mongodb.MongoClientOptions = {
|
|
193
|
+
maxPoolSize: descriptor.maxPoolSize ?? 100,
|
|
194
|
+
maxIdleTimeMS: descriptor.maxIdleTimeMS ?? 300000,
|
|
195
|
+
serverSelectionTimeoutMS:
|
|
196
|
+
budget?.remainingMs() ?? descriptor.serverSelectionTimeoutMS ?? 30000,
|
|
197
|
+
...(budget ? { connectTimeoutMS: budget.remainingMs() } : {}),
|
|
198
|
+
socketTimeoutMS: descriptor.socketTimeoutMS ?? 30000,
|
|
199
|
+
retryWrites: true,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
candidateClient = new plugins.mongodb.MongoClient(finalConnectionUrl, clientOptions);
|
|
203
|
+
this.pendingClient = candidateClient;
|
|
204
|
+
const connectingClient = candidateClient;
|
|
205
|
+
let cancellationCleanup: Promise<void> | undefined;
|
|
206
|
+
const onAbort = () => {
|
|
207
|
+
cancellationCleanup ??= connectingClient.close();
|
|
208
|
+
// The connection and this cleanup are both joined below.
|
|
209
|
+
void cancellationCleanup.catch(() => {});
|
|
210
|
+
};
|
|
211
|
+
budget?.signal.addEventListener('abort', onAbort, { once: true });
|
|
212
|
+
try {
|
|
213
|
+
budget?.check();
|
|
214
|
+
await connectingClient.connect();
|
|
215
|
+
budget?.check();
|
|
216
|
+
} finally {
|
|
217
|
+
budget?.signal.removeEventListener('abort', onAbort);
|
|
218
|
+
if (cancellationCleanup) await cancellationCleanup;
|
|
219
|
+
}
|
|
220
|
+
const candidateDb = candidateClient.db(
|
|
221
|
+
this.smartdataOptions.mongoDbName,
|
|
222
|
+
);
|
|
223
|
+
for (const collection of this.smartdataCollectionMap.getArray()) {
|
|
224
|
+
collection.resetForDatabaseReconnect();
|
|
225
|
+
}
|
|
226
|
+
budget?.check();
|
|
227
|
+
this.mongoDbClient = candidateClient;
|
|
228
|
+
this.mongoDb = candidateDb;
|
|
229
|
+
candidateClient = undefined;
|
|
230
|
+
this.pendingClient = undefined;
|
|
231
|
+
this.status = 'connected';
|
|
232
|
+
this.transitionLifecycle('connected');
|
|
233
|
+
this.statusConnectedDeferred.resolve();
|
|
234
|
+
logger.log('info', `Connected to database ${this.smartdataOptions.mongoDbName}`);
|
|
235
|
+
} catch (error) {
|
|
236
|
+
let cleanupError: unknown;
|
|
237
|
+
if (candidateClient) {
|
|
238
|
+
try {
|
|
239
|
+
// A cancelled connect may establish resources after its first close.
|
|
240
|
+
await candidateClient.close();
|
|
241
|
+
this.pendingClient = undefined;
|
|
242
|
+
} catch (errorArg) {
|
|
243
|
+
cleanupError = errorArg;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
this.status = 'disconnected';
|
|
247
|
+
this.transitionLifecycle(this.pendingClient ? 'close_failed' : 'connection_failed');
|
|
248
|
+
logger.log('error', 'Failed to connect to the SmartData database.');
|
|
249
|
+
if (budget) {
|
|
250
|
+
throw new SmartdataPersistenceError('unsupported_operation', this.pendingClient
|
|
251
|
+
? 'SmartData connection setup and cleanup failed; close must be retried.'
|
|
252
|
+
: 'SmartData connection setup failed or was cancelled.');
|
|
253
|
+
}
|
|
254
|
+
if (cleanupError) throw new AggregateError([error, cleanupError],
|
|
255
|
+
'SmartData connection setup and cleanup failed; close must be retried.');
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
} finally {
|
|
259
|
+
this.endLifecycleOperation('init');
|
|
260
|
+
budget?.close();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* closes the connection to the databse
|
|
266
|
+
*/
|
|
267
|
+
public async close(optionsArg: ISmartdataCloseOptions = {}): Promise<void> {
|
|
268
|
+
this.assertLifecycleOperationCanBegin('close');
|
|
269
|
+
const databaseToDrop = this.resolveDatabaseToDrop(optionsArg);
|
|
270
|
+
const timeoutMs = Object.hasOwn(optionsArg, 'timeoutMs') ? optionsArg.timeoutMs : undefined;
|
|
271
|
+
const budget = timeoutMs === undefined ? undefined : new SmartdataOperationBudget(timeoutMs);
|
|
272
|
+
this.beginLifecycleOperation('close');
|
|
273
|
+
this.transitionLifecycle('closing');
|
|
274
|
+
this.status = 'disconnected';
|
|
275
|
+
const mongoDbClient = this.pendingClient ?? this.mongoDbClient;
|
|
276
|
+
try {
|
|
277
|
+
const closeErrors: unknown[] = [];
|
|
278
|
+
try {
|
|
279
|
+
await invalidateSmartdataSessions(this);
|
|
280
|
+
} catch (errorArg) {
|
|
281
|
+
closeErrors.push(
|
|
282
|
+
...(unwrapSmartdataSessionInvalidationErrors(errorArg) ?? [errorArg]),
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
if (databaseToDrop) {
|
|
286
|
+
try {
|
|
287
|
+
const databaseDropped = await databaseToDrop.dropDatabase(budget?.operationOptions());
|
|
288
|
+
if (!databaseDropped) {
|
|
289
|
+
throw new SmartdataPersistenceError(
|
|
290
|
+
'unsupported_operation',
|
|
291
|
+
'MongoDB did not acknowledge the requested database removal.',
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
} catch (errorArg) {
|
|
295
|
+
closeErrors.push(errorArg);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
await mongoDbClient?.close();
|
|
300
|
+
this.pendingClient = undefined;
|
|
301
|
+
} catch (errorArg) {
|
|
302
|
+
closeErrors.push(errorArg);
|
|
303
|
+
}
|
|
304
|
+
if (closeErrors.length > 0) {
|
|
305
|
+
this.transitionLifecycle('close_failed');
|
|
306
|
+
if (budget) throw new SmartdataPersistenceError('unsupported_operation',
|
|
307
|
+
'SmartData database cleanup failed; close must be retried.');
|
|
308
|
+
if (closeErrors.length === 1) {
|
|
309
|
+
throw closeErrors[0];
|
|
310
|
+
}
|
|
311
|
+
throw new AggregateError(
|
|
312
|
+
closeErrors,
|
|
313
|
+
'Multiple SmartData database cleanup operations failed.',
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
this.transitionLifecycle('closed');
|
|
317
|
+
logger.log('info', `disconnected from database ${this.smartdataOptions.mongoDbName}`);
|
|
318
|
+
} finally {
|
|
319
|
+
this.endLifecycleOperation('close');
|
|
320
|
+
budget?.close();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Performs a bounded, read-only round trip to verify database readiness.
|
|
326
|
+
*/
|
|
327
|
+
public async checkReadiness(
|
|
328
|
+
optionsArg: ISmartdataReadinessOptions = {},
|
|
329
|
+
): Promise<TSmartdataReadinessResult> {
|
|
330
|
+
const startedAt = performance.now();
|
|
331
|
+
const timeoutMs = optionsArg.timeoutMs ?? readinessDefaultTimeoutMs;
|
|
332
|
+
if (
|
|
333
|
+
!Number.isSafeInteger(timeoutMs) ||
|
|
334
|
+
timeoutMs <= 0 ||
|
|
335
|
+
timeoutMs > readinessMaximumTimeoutMs
|
|
336
|
+
) {
|
|
337
|
+
throw new SmartdataPersistenceError(
|
|
338
|
+
'invalid_argument',
|
|
339
|
+
`Readiness timeoutMs must be a positive safe integer no greater than ${readinessMaximumTimeoutMs}.`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const lifecycleReason = this.getReadinessLifecycleReason();
|
|
344
|
+
if (lifecycleReason) {
|
|
345
|
+
return this.createReadinessFailure(lifecycleReason, startedAt);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const signal = optionsArg.signal;
|
|
349
|
+
if (signal?.aborted) {
|
|
350
|
+
return this.createReadinessFailure('aborted', startedAt);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const lifecycleEpoch = this.lifecycleEpoch;
|
|
354
|
+
const mongoDb = this.mongoDb;
|
|
355
|
+
const mongoDbClient = this.mongoDbClient;
|
|
356
|
+
let response: plugins.mongodb.BSON.Document;
|
|
357
|
+
try {
|
|
358
|
+
response = await mongoDb.command(
|
|
359
|
+
{ ping: 1 },
|
|
360
|
+
{
|
|
361
|
+
timeoutMS: timeoutMs,
|
|
362
|
+
signal,
|
|
363
|
+
},
|
|
364
|
+
);
|
|
365
|
+
} catch (error) {
|
|
366
|
+
if (signal?.aborted) {
|
|
367
|
+
return this.createReadinessFailure('aborted', startedAt);
|
|
368
|
+
}
|
|
369
|
+
if (
|
|
370
|
+
this.lifecycleEpoch !== lifecycleEpoch ||
|
|
371
|
+
this.mongoDb !== mongoDb ||
|
|
372
|
+
this.mongoDbClient !== mongoDbClient
|
|
373
|
+
) {
|
|
374
|
+
return this.createReadinessFailure(
|
|
375
|
+
this.getReadinessLifecycleReason() ?? 'unavailable',
|
|
376
|
+
startedAt,
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
if (error instanceof plugins.mongodb.MongoOperationTimeoutError) {
|
|
380
|
+
return this.createReadinessFailure('timeout', startedAt);
|
|
381
|
+
}
|
|
382
|
+
return this.createReadinessFailure('unavailable', startedAt);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (
|
|
386
|
+
this.lifecycleEpoch !== lifecycleEpoch ||
|
|
387
|
+
this.mongoDb !== mongoDb ||
|
|
388
|
+
this.mongoDbClient !== mongoDbClient
|
|
389
|
+
) {
|
|
390
|
+
return this.createReadinessFailure(
|
|
391
|
+
this.getReadinessLifecycleReason() ?? 'unavailable',
|
|
392
|
+
startedAt,
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (response.ok !== 1) {
|
|
397
|
+
return this.createReadinessFailure('unavailable', startedAt);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
ready: true,
|
|
402
|
+
status: 'ready',
|
|
403
|
+
durationMs: performance.now() - startedAt,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Starts a raw MongoDB session. Use createSession() when every transaction
|
|
409
|
+
* operation goes through SmartData and stable persistence errors are needed.
|
|
410
|
+
*/
|
|
411
|
+
public startSession(): plugins.mongodb.ClientSession {
|
|
412
|
+
return this.mongoDbClient.startSession();
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Creates a SmartData-owned session for model transactions.
|
|
417
|
+
*/
|
|
418
|
+
public createSession(): SmartdataSession {
|
|
419
|
+
return createSmartdataSession(this);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Creates a narrowly scoped MongoDB administration facade bound to this
|
|
424
|
+
* SmartData lifecycle. Applications never need direct driver access.
|
|
425
|
+
*/
|
|
426
|
+
public createMongoAdministration(): SmartdataMongoAdministration {
|
|
427
|
+
return new SmartdataMongoAdministration(this);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Observe all namespaces, indexes and bounded counts without initializing models. */
|
|
431
|
+
public async inspectNamespace(
|
|
432
|
+
optionsArg?: ISmartdataNamespaceInspectionOptions,
|
|
433
|
+
): Promise<ISmartdataNamespaceInspection> {
|
|
434
|
+
return inspectSmartdataNamespace(this, optionsArg);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** @internal Runs inspection or explicit model preparation against one connection generation. */
|
|
438
|
+
public async [collectionTopologyDbInspectionSymbol]<TResult>(
|
|
439
|
+
operationArg: (mongoDbArg: plugins.mongodb.Db, assertCurrentArg: () => void) => Promise<TResult>,
|
|
440
|
+
): Promise<TResult> {
|
|
441
|
+
if (
|
|
442
|
+
this.lifecycleState !== 'connected' ||
|
|
443
|
+
this.status !== 'connected' ||
|
|
444
|
+
!this.mongoDb ||
|
|
445
|
+
!this.mongoDbClient ||
|
|
446
|
+
this.mongoDb.client !== this.mongoDbClient
|
|
447
|
+
) {
|
|
448
|
+
throw new SmartdataPersistenceError(
|
|
449
|
+
'unsupported_operation',
|
|
450
|
+
'Collection topology inspection requires a connected SmartdataDb.',
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
const lifecycleEpoch = this.lifecycleEpoch;
|
|
454
|
+
const mongoDb = this.mongoDb;
|
|
455
|
+
const mongoDbClient = this.mongoDbClient;
|
|
456
|
+
const connectionIsCurrent = () =>
|
|
457
|
+
this.lifecycleState === 'connected' &&
|
|
458
|
+
this.status === 'connected' &&
|
|
459
|
+
this.lifecycleEpoch === lifecycleEpoch &&
|
|
460
|
+
this.mongoDb === mongoDb &&
|
|
461
|
+
this.mongoDbClient === mongoDbClient &&
|
|
462
|
+
mongoDb.client === mongoDbClient;
|
|
463
|
+
let result: TResult;
|
|
464
|
+
try {
|
|
465
|
+
result = await operationArg(mongoDb, () => {
|
|
466
|
+
if (!connectionIsCurrent()) {
|
|
467
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'SmartData connection changed during operation.');
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
} catch {
|
|
471
|
+
if (!connectionIsCurrent()) {
|
|
472
|
+
throw new SmartdataPersistenceError(
|
|
473
|
+
'unsupported_operation',
|
|
474
|
+
'SmartData connection changed during collection topology inspection.',
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
throw new SmartdataPersistenceError(
|
|
478
|
+
'unsupported_operation',
|
|
479
|
+
'Collection topology inspection failed.',
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
if (!connectionIsCurrent()) {
|
|
483
|
+
throw new SmartdataPersistenceError(
|
|
484
|
+
'unsupported_operation',
|
|
485
|
+
'SmartData connection changed during collection topology inspection.',
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// handle table to class distribution
|
|
492
|
+
|
|
493
|
+
public addCollection(SmartdataCollectionArg: SmartdataCollection<any>) {
|
|
494
|
+
this.smartdataCollectionMap.add(SmartdataCollectionArg);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Gets a collection's name and returns a SmartdataCollection instance
|
|
499
|
+
* @param nameArg
|
|
500
|
+
* @returns DbTable
|
|
501
|
+
*/
|
|
502
|
+
public async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> {
|
|
503
|
+
const resultCollection = await this.smartdataCollectionMap.find(async (dbTableArg) => {
|
|
504
|
+
return dbTableArg.collectionName === nameArg;
|
|
505
|
+
});
|
|
506
|
+
return resultCollection;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
private beginLifecycleOperation(operationArg: TSmartdataDbLifecycleOperation): void {
|
|
510
|
+
this.assertLifecycleOperationCanBegin(operationArg);
|
|
511
|
+
this.activeLifecycleOperation = operationArg;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
private assertLifecycleOperationCanBegin(
|
|
515
|
+
operationArg: TSmartdataDbLifecycleOperation,
|
|
516
|
+
): void {
|
|
517
|
+
if (this.activeLifecycleOperation) {
|
|
518
|
+
throw new SmartdataPersistenceError(
|
|
519
|
+
'unsupported_operation',
|
|
520
|
+
`Cannot start SmartData database ${operationArg} while ${this.activeLifecycleOperation} is still running.`,
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
if (
|
|
524
|
+
operationArg === 'init' &&
|
|
525
|
+
(this.lifecycleState === 'connected' ||
|
|
526
|
+
this.lifecycleState === 'close_failed')
|
|
527
|
+
) {
|
|
528
|
+
throw new SmartdataPersistenceError(
|
|
529
|
+
'unsupported_operation',
|
|
530
|
+
`Cannot start SmartData database init while the existing client is ${this.lifecycleState}.`,
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
private resolveDatabaseToDrop(
|
|
536
|
+
optionsArg: ISmartdataCloseOptions,
|
|
537
|
+
): plugins.mongodb.Db | undefined {
|
|
538
|
+
const options = assertDataOptions(optionsArg, ['dropDatabase', 'timeoutMs']);
|
|
539
|
+
if (!Object.hasOwn(options, 'dropDatabase')) {
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
const dropDatabaseOptions = assertExactDataObject(
|
|
543
|
+
options.dropDatabase,
|
|
544
|
+
['expectedDatabaseName'],
|
|
545
|
+
'SmartData dropDatabase options',
|
|
546
|
+
);
|
|
547
|
+
const expectedDatabaseName = dropDatabaseOptions.expectedDatabaseName;
|
|
548
|
+
if (
|
|
549
|
+
typeof expectedDatabaseName !== 'string' ||
|
|
550
|
+
expectedDatabaseName.length === 0 ||
|
|
551
|
+
expectedDatabaseName.trim() !== expectedDatabaseName
|
|
552
|
+
) {
|
|
553
|
+
throw new SmartdataPersistenceError(
|
|
554
|
+
'invalid_argument',
|
|
555
|
+
'SmartData expectedDatabaseName must be a non-empty string without surrounding whitespace.',
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
if (
|
|
559
|
+
this.lifecycleState !== 'connected' ||
|
|
560
|
+
this.status !== 'connected' ||
|
|
561
|
+
!this.mongoDbClient ||
|
|
562
|
+
!this.mongoDb
|
|
563
|
+
) {
|
|
564
|
+
throw new SmartdataPersistenceError(
|
|
565
|
+
'unsupported_operation',
|
|
566
|
+
'SmartData can remove a database only from a connected lifecycle.',
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
if (this.mongoDb.client !== this.mongoDbClient) {
|
|
570
|
+
throw new SmartdataPersistenceError(
|
|
571
|
+
'invalid_configuration',
|
|
572
|
+
'SmartData database and client bindings are inconsistent.',
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
const boundDatabaseName = this.mongoDb.databaseName;
|
|
576
|
+
if (expectedDatabaseName !== boundDatabaseName) {
|
|
577
|
+
throw new SmartdataPersistenceError(
|
|
578
|
+
'invalid_argument',
|
|
579
|
+
'SmartData expectedDatabaseName does not match the connected database.',
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
if (this.smartdataOptions.mongoDbName !== boundDatabaseName) {
|
|
583
|
+
throw new SmartdataPersistenceError(
|
|
584
|
+
'invalid_configuration',
|
|
585
|
+
'SmartData database descriptor no longer matches the connected database.',
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
return this.mongoDb;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private endLifecycleOperation(operationArg: TSmartdataDbLifecycleOperation): void {
|
|
592
|
+
if (this.activeLifecycleOperation === operationArg) {
|
|
593
|
+
this.activeLifecycleOperation = null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private transitionLifecycle(stateArg: TSmartdataDbLifecycleState): void {
|
|
598
|
+
this.lifecycleState = stateArg;
|
|
599
|
+
this.lifecycleEpoch++;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
private getReadinessLifecycleReason():
|
|
603
|
+
| Exclude<
|
|
604
|
+
TSmartdataReadinessFailureReason,
|
|
605
|
+
'aborted' | 'timeout' | 'unavailable'
|
|
606
|
+
>
|
|
607
|
+
| undefined {
|
|
608
|
+
switch (this.lifecycleState) {
|
|
609
|
+
case 'initial':
|
|
610
|
+
return 'not_initialized';
|
|
611
|
+
case 'connecting':
|
|
612
|
+
return 'connecting';
|
|
613
|
+
case 'connection_failed':
|
|
614
|
+
return 'connection_failed';
|
|
615
|
+
case 'closing':
|
|
616
|
+
return 'closing';
|
|
617
|
+
case 'closed':
|
|
618
|
+
return 'closed';
|
|
619
|
+
case 'close_failed':
|
|
620
|
+
return 'close_failed';
|
|
621
|
+
case 'connected':
|
|
622
|
+
return undefined;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
private createReadinessFailure(
|
|
627
|
+
reasonArg: TSmartdataReadinessFailureReason,
|
|
628
|
+
startedAtArg: number,
|
|
629
|
+
): TSmartdataReadinessResult {
|
|
630
|
+
return {
|
|
631
|
+
ready: false,
|
|
632
|
+
status: 'unavailable',
|
|
633
|
+
reason: reasonArg,
|
|
634
|
+
durationMs: performance.now() - startedAtArg,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|