@lossless.org/client 1.4.1 → 1.5.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/core/interfaces.d.ts +7 -0
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/nosqldb/classes.collection.js +2 -3
- package/dist_ts/nosqldb/classes.connection.d.ts +8 -3
- package/dist_ts/nosqldb/classes.connection.js +11 -6
- package/dist_ts/nosqldb/classes.db.d.ts +13 -0
- package/dist_ts/nosqldb/classes.db.js +28 -1
- package/dist_ts/nosqldb/classes.doc.js +10 -2
- package/dist_ts/nosqldb/classes.easystore.d.ts +13 -0
- package/dist_ts/nosqldb/classes.easystore.js +16 -1
- package/dist_ts/nosqldb/engineidentity.d.ts +31 -0
- package/dist_ts/nosqldb/engineidentity.js +105 -0
- package/dist_ts/nosqldb/index.d.ts +2 -0
- package/dist_ts/nosqldb/index.js +1 -1
- package/dist_ts/nosqldb/lineage.js +3 -1
- package/dist_ts/objectstorage/classes.connection.js +2 -2
- package/dist_ts/sqldb/classes.clickhouseconnection.js +3 -2
- package/dist_ts/sqldb/classes.sqlconnection.js +2 -2
- package/package.json +2 -2
- package/readme.md +13 -10
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/interfaces.ts +7 -0
- package/ts/index.ts +1 -1
- package/ts/nosqldb/classes.collection.ts +1 -2
- package/ts/nosqldb/classes.connection.ts +19 -7
- package/ts/nosqldb/classes.db.ts +38 -0
- package/ts/nosqldb/classes.doc.ts +14 -1
- package/ts/nosqldb/classes.easystore.ts +16 -0
- package/ts/nosqldb/engineidentity.ts +153 -0
- package/ts/nosqldb/index.ts +11 -0
- package/ts/nosqldb/lineage.ts +2 -0
- package/ts/objectstorage/classes.connection.ts +1 -1
- package/ts/sqldb/classes.clickhouseconnection.ts +2 -1
- package/ts/sqldb/classes.sqlconnection.ts +1 -1
|
@@ -2369,8 +2369,7 @@ export class SmartdataCollection<T> {
|
|
|
2369
2369
|
opts: (plugins.mongodb.ChangeStreamOptions & { bufferTimeMs?: number }) = {},
|
|
2370
2370
|
smartdataDbDocArg?: typeof SmartDataDbDoc,
|
|
2371
2371
|
): Promise<SmartdataDbWatcher> {
|
|
2372
|
-
if (
|
|
2373
|
-
(this.smartdataDb.capabilities as { changeStreams?: string }).changeStreams === 'unsupported') {
|
|
2372
|
+
if (this.smartdataDb.capabilities?.changeStreams === 'unsupported') {
|
|
2374
2373
|
throw new LosslessClientError('unsupported_capability', 'Change streams are unsupported by this backend.');
|
|
2375
2374
|
}
|
|
2376
2375
|
await this.init();
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { SmartdataDb } from './classes.db.js';
|
|
2
|
+
import {
|
|
3
|
+
composeSmartdataCapabilities,
|
|
4
|
+
smartdataCompositeGrouping,
|
|
5
|
+
type ISmartdataEngineIdentity,
|
|
6
|
+
type TSmartdataEngineBackend,
|
|
7
|
+
} from './engineidentity.js';
|
|
2
8
|
import type { ICapabilities, IOperationOptions, IReadiness } from '../core/interfaces.js';
|
|
3
9
|
|
|
4
10
|
export interface INoSqlConnectionOptions {
|
|
5
|
-
backend:
|
|
11
|
+
backend: TSmartdataEngineBackend;
|
|
6
12
|
url: string;
|
|
7
13
|
database: string;
|
|
8
14
|
username?: string;
|
|
@@ -11,17 +17,23 @@ export interface INoSqlConnectionOptions {
|
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
export class NoSqlConnection extends SmartdataDb {
|
|
14
|
-
public readonly backend:
|
|
15
|
-
|
|
20
|
+
public readonly backend: TSmartdataEngineBackend;
|
|
21
|
+
private declaredCapabilities: ICapabilities;
|
|
22
|
+
/** A declared backend states its capabilities before the first connect. */
|
|
23
|
+
public override get capabilities(): ICapabilities { return this.declaredCapabilities; }
|
|
16
24
|
constructor(public readonly options: INoSqlConnectionOptions) {
|
|
17
25
|
super({ mongoDbUrl: options.url, mongoDbName: options.database,
|
|
18
26
|
mongoDbUser: options.username, mongoDbPass: options.password,
|
|
19
27
|
...(options.connectionLimit === undefined ? {} : { maxPoolSize: options.connectionLimit }) });
|
|
20
28
|
this.backend = options.backend;
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
this.declaredCapabilities = composeSmartdataCapabilities(this.backend,
|
|
30
|
+
smartdataCompositeGrouping(this.engineIdentity));
|
|
31
|
+
}
|
|
32
|
+
/** The declared backend outranks the probe; only the probe knows the engine release. */
|
|
33
|
+
protected override applyEngineIdentity(identityArg: ISmartdataEngineIdentity): void {
|
|
34
|
+
super.applyEngineIdentity(identityArg);
|
|
35
|
+
this.declaredCapabilities = composeSmartdataCapabilities(this.backend,
|
|
36
|
+
smartdataCompositeGrouping(identityArg));
|
|
25
37
|
}
|
|
26
38
|
public async connect(options: IOperationOptions = {}): Promise<void> { await this.init(options); }
|
|
27
39
|
public async ready(options: IOperationOptions = {}): Promise<IReadiness> {
|
package/ts/nosqldb/classes.db.ts
CHANGED
|
@@ -22,6 +22,15 @@ export type { TSmartdataOrdinarySession } from './classes.session.js';
|
|
|
22
22
|
|
|
23
23
|
import { logger } from './logging.js';
|
|
24
24
|
import { assertDataOptions, SmartdataOperationBudget } from './classes.operationbudget.js';
|
|
25
|
+
import {
|
|
26
|
+
composeSmartdataCapabilities,
|
|
27
|
+
probeSmartdataEngineIdentity,
|
|
28
|
+
smartdataCompositeGrouping,
|
|
29
|
+
smartdataEngineBackend,
|
|
30
|
+
unidentifiedSmartdataEngine,
|
|
31
|
+
type ISmartdataEngineIdentity,
|
|
32
|
+
} from './engineidentity.js';
|
|
33
|
+
import type { ICapabilities } from '../core/interfaces.js';
|
|
25
34
|
|
|
26
35
|
/**
|
|
27
36
|
* interface - indicates the connection status of the db
|
|
@@ -139,6 +148,8 @@ export class SmartdataDb {
|
|
|
139
148
|
private lifecycleEpoch = 0;
|
|
140
149
|
private activeLifecycleOperation: TSmartdataDbLifecycleOperation | null = null;
|
|
141
150
|
private pendingClient?: plugins.mongodb.MongoClient;
|
|
151
|
+
private engineIdentityState: ISmartdataEngineIdentity = unidentifiedSmartdataEngine;
|
|
152
|
+
private capabilitiesState: ICapabilities | undefined;
|
|
142
153
|
|
|
143
154
|
constructor(smartdataOptions: plugins.tsclass.database.IMongoDescriptor) {
|
|
144
155
|
this.smartdataOptions = smartdataOptions;
|
|
@@ -146,6 +157,28 @@ export class SmartdataDb {
|
|
|
146
157
|
void this.statusConnectedDeferred.promise.catch(() => {});
|
|
147
158
|
}
|
|
148
159
|
|
|
160
|
+
/** What the last `init()` identified the connected engine as. */
|
|
161
|
+
public get engineIdentity(): ISmartdataEngineIdentity {
|
|
162
|
+
return this.engineIdentityState;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* What the identified engine can do, or `undefined` while no engine is
|
|
167
|
+
* identified. A caller must read the absent statement as "not available".
|
|
168
|
+
*/
|
|
169
|
+
public get capabilities(): ICapabilities | undefined {
|
|
170
|
+
return this.capabilitiesState;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Records the identity `init()` read and restates the capabilities it implies. */
|
|
174
|
+
protected applyEngineIdentity(identityArg: ISmartdataEngineIdentity): void {
|
|
175
|
+
this.engineIdentityState = identityArg;
|
|
176
|
+
const backend = smartdataEngineBackend(identityArg);
|
|
177
|
+
this.capabilitiesState = backend === undefined
|
|
178
|
+
? undefined
|
|
179
|
+
: composeSmartdataCapabilities(backend, smartdataCompositeGrouping(identityArg));
|
|
180
|
+
}
|
|
181
|
+
|
|
149
182
|
// easystore
|
|
150
183
|
public async createEasyStore<T = unknown>(nameIdArg: string): Promise<EasyStore<T>> {
|
|
151
184
|
const easyStore = new EasyStore<T>(nameIdArg, this);
|
|
@@ -224,6 +257,11 @@ export class SmartdataDb {
|
|
|
224
257
|
collection.resetForDatabaseReconnect();
|
|
225
258
|
}
|
|
226
259
|
budget?.check();
|
|
260
|
+
// The engine is asked what it is before the connection is published, so
|
|
261
|
+
// no operation can run against a database whose capabilities are stale.
|
|
262
|
+
this.applyEngineIdentity(await probeSmartdataEngineIdentity(candidateDb, budget));
|
|
263
|
+
// The probe absorbs its own failures, so a budget that expired during it must still refuse here.
|
|
264
|
+
budget?.check();
|
|
227
265
|
this.mongoDbClient = candidateClient;
|
|
228
266
|
this.mongoDb = candidateDb;
|
|
229
267
|
candidateClient = undefined;
|
|
@@ -5001,6 +5001,20 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5001
5001
|
120_000,
|
|
5002
5002
|
);
|
|
5003
5003
|
const timeoutMS = requireBoundedInteger(timeoutMSOption, 'Grouped totals timeoutMS', 120_000);
|
|
5004
|
+
const collection: SmartdataCollection<T> = (this as any).collection;
|
|
5005
|
+
if (
|
|
5006
|
+
groupByFields.length === 2
|
|
5007
|
+
&& collection.smartdataDb.capabilities?.compositeGrouping !== 'exact'
|
|
5008
|
+
) {
|
|
5009
|
+
// The backend would answer a composite group key without evaluating it,
|
|
5010
|
+
// and a wrong total that never raises is worse than no total at all.
|
|
5011
|
+
throw new SmartdataPersistenceError(
|
|
5012
|
+
'unsupported_operation',
|
|
5013
|
+
`Grouped totals cannot group by "${groupByFields[0]}" and "${groupByFields[1]}" together: `
|
|
5014
|
+
+ 'this backend does not evaluate a composite group key exactly. Group by one field per '
|
|
5015
|
+
+ `call, such as groupBy: ["${groupByFields[0]}"].`,
|
|
5016
|
+
);
|
|
5017
|
+
}
|
|
5004
5018
|
const groupStage: Record<string, unknown> = {
|
|
5005
5019
|
_id: groupByFields.length === 1
|
|
5006
5020
|
? '$' + groupByFields[0]
|
|
@@ -5012,7 +5026,6 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
|
|
|
5012
5026
|
for (const [index, sumField] of sumFields.entries()) {
|
|
5013
5027
|
groupStage['__groupedTotalsSum' + index] = { $sum: '$' + sumField };
|
|
5014
5028
|
}
|
|
5015
|
-
const collection: SmartdataCollection<T> = (this as any).collection;
|
|
5016
5029
|
const rows = await collection.aggregateGroupedTotals(
|
|
5017
5030
|
filterOption !== undefined
|
|
5018
5031
|
? (this as any).normalizeReadFilter(filterOption)
|
|
@@ -50,6 +50,22 @@ export class EasyStore<T> {
|
|
|
50
50
|
this.easyStoreClass = getEasyStoreClassForDb<T>(smartdataDbRefArg);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Installs the store's declared `nameId` index before any caller opens a
|
|
55
|
+
* transaction, and resolves once the collection is initialized. Idempotent:
|
|
56
|
+
* every call after the first returns without touching the backend.
|
|
57
|
+
*
|
|
58
|
+
* A model's declared indexes are created on the first model-API touch of its
|
|
59
|
+
* collection, as unsessioned DDL. While a transaction holds that collection
|
|
60
|
+
* the DDL waits for it, so a first `readKey()`/`writeKey()` raced against a
|
|
61
|
+
* transaction stalls until the client deadline instead of answering. A
|
|
62
|
+
* consumer that opens transactions on the same database calls this once
|
|
63
|
+
* during startup, before the store is read or written.
|
|
64
|
+
*/
|
|
65
|
+
public async ensureInitialized(): Promise<void> {
|
|
66
|
+
await (this.easyStoreClass as typeof SmartDataDbDoc).ensureInitialized();
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
private easyStorePromise?: Promise<InstanceType<typeof this.easyStoreClass>>;
|
|
54
70
|
private async getEasyStore(): Promise<InstanceType<typeof this.easyStoreClass>> {
|
|
55
71
|
if (this.easyStorePromise) {
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import type { SmartdataOperationBudget } from './classes.operationbudget.js';
|
|
3
|
+
import type { ICapabilities, TCompositeGrouping } from '../core/interfaces.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* What the connected engine states it is. `unknown` is the fail-closed answer:
|
|
7
|
+
* the engine either does not implement the identity probe or does not answer it
|
|
8
|
+
* in a shape that identifies anything.
|
|
9
|
+
*/
|
|
10
|
+
export type TSmartdataEngineProduct = 'NoSQLDB' | 'MongoDB' | 'unknown';
|
|
11
|
+
|
|
12
|
+
/** The document backend a connection is actually talking to. */
|
|
13
|
+
export type TSmartdataEngineBackend = 'nosqldb' | 'mongodb';
|
|
14
|
+
|
|
15
|
+
export interface ISmartdataEngineIdentity {
|
|
16
|
+
readonly product: TSmartdataEngineProduct;
|
|
17
|
+
/**
|
|
18
|
+
* The engine's own version — NoSQLDB's released package version, MongoDB's
|
|
19
|
+
* server version — or `null` when the engine states none.
|
|
20
|
+
*/
|
|
21
|
+
readonly version: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const unidentifiedSmartdataEngine: ISmartdataEngineIdentity = Object.freeze({
|
|
25
|
+
product: 'unknown',
|
|
26
|
+
version: null,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The NoSQLDB release that evaluates a composite `$group` key instead of
|
|
31
|
+
* answering with the literal field paths: @lossless.org/nosqldb 10.5.0.
|
|
32
|
+
*/
|
|
33
|
+
const compositeGroupingEngineRelease = '10.5.0';
|
|
34
|
+
|
|
35
|
+
const parseEngineVersion = (versionArg: string): readonly number[] | undefined => {
|
|
36
|
+
const parts = versionArg.split('.');
|
|
37
|
+
if (parts.length !== 3) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const numbers = parts.map((partArg) =>
|
|
41
|
+
/^\d+$/.test(partArg) ? Number(partArg) : Number.NaN,
|
|
42
|
+
);
|
|
43
|
+
return numbers.some((numberArg) => !Number.isSafeInteger(numberArg)) ? undefined : numbers;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Compares two release versions. A version this cannot parse — a prerelease or
|
|
48
|
+
* any other shape — counts as below the minimum, so an engine only ever gains a
|
|
49
|
+
* capability by stating a release that plainly carries it.
|
|
50
|
+
*/
|
|
51
|
+
const engineVersionReaches = (versionArg: string, minimumArg: string): boolean => {
|
|
52
|
+
const version = parseEngineVersion(versionArg);
|
|
53
|
+
const minimum = parseEngineVersion(minimumArg);
|
|
54
|
+
if (version === undefined || minimum === undefined) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
for (const [index, minimumPart] of minimum.entries()) {
|
|
58
|
+
if (version[index] !== minimumPart) {
|
|
59
|
+
return version[index] > minimumPart;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const smartdataEngineBackend = (
|
|
66
|
+
identityArg: ISmartdataEngineIdentity,
|
|
67
|
+
): TSmartdataEngineBackend | undefined => {
|
|
68
|
+
switch (identityArg.product) {
|
|
69
|
+
case 'NoSQLDB':
|
|
70
|
+
return 'nosqldb';
|
|
71
|
+
case 'MongoDB':
|
|
72
|
+
return 'mongodb';
|
|
73
|
+
case 'unknown':
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const smartdataCompositeGrouping = (
|
|
79
|
+
identityArg: ISmartdataEngineIdentity,
|
|
80
|
+
): TCompositeGrouping => {
|
|
81
|
+
switch (identityArg.product) {
|
|
82
|
+
case 'MongoDB':
|
|
83
|
+
return 'exact';
|
|
84
|
+
case 'NoSQLDB':
|
|
85
|
+
return identityArg.version !== null
|
|
86
|
+
&& engineVersionReaches(identityArg.version, compositeGroupingEngineRelease)
|
|
87
|
+
? 'exact'
|
|
88
|
+
: 'unsupported';
|
|
89
|
+
case 'unknown':
|
|
90
|
+
return 'unsupported';
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const composeSmartdataCapabilities = (
|
|
95
|
+
backendArg: TSmartdataEngineBackend,
|
|
96
|
+
compositeGroupingArg: TCompositeGrouping,
|
|
97
|
+
): ICapabilities => {
|
|
98
|
+
const capabilities: ICapabilities = {
|
|
99
|
+
backend: backendArg,
|
|
100
|
+
transactions: backendArg === 'nosqldb' ? 'available' : 'unknown',
|
|
101
|
+
changeStreams: backendArg === 'nosqldb' ? 'unsupported' : 'unknown',
|
|
102
|
+
compositeGrouping: compositeGroupingArg,
|
|
103
|
+
objectMetrics: 'unsupported',
|
|
104
|
+
diskResidentScans: 'available',
|
|
105
|
+
};
|
|
106
|
+
return Object.freeze(capabilities);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const isDocumentRecord = (valueArg: unknown): valueArg is Record<string, unknown> =>
|
|
110
|
+
typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
|
|
111
|
+
|
|
112
|
+
const readSmartdataEngineIdentity = (
|
|
113
|
+
answerArg: plugins.mongodb.Document,
|
|
114
|
+
): ISmartdataEngineIdentity => {
|
|
115
|
+
const vendorDocument: unknown = answerArg.nosqldb;
|
|
116
|
+
if (vendorDocument === undefined) {
|
|
117
|
+
// No vendor document: a MongoDB `buildInfo`, whose `version` is the server's own.
|
|
118
|
+
const version: unknown = answerArg.version;
|
|
119
|
+
return Object.freeze({
|
|
120
|
+
product: 'MongoDB',
|
|
121
|
+
version: typeof version === 'string' ? version : null,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
isDocumentRecord(vendorDocument)
|
|
126
|
+
&& vendorDocument.product === 'NoSQLDB'
|
|
127
|
+
&& typeof vendorDocument.version === 'string'
|
|
128
|
+
) {
|
|
129
|
+
return Object.freeze({ product: 'NoSQLDB', version: vendorDocument.version });
|
|
130
|
+
}
|
|
131
|
+
// A vendor document that states no product and version identifies nothing.
|
|
132
|
+
return unidentifiedSmartdataEngine;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Asks the connected engine what it is with one `buildInfo` command. NoSQLDB
|
|
137
|
+
* answers it pre-authentication and from build metadata alone; MongoDB answers
|
|
138
|
+
* it for every connection. An engine that refuses the command — NoSQLDB 8.0.2
|
|
139
|
+
* answers `CommandNotFound` (59) — stays unidentified, and an unidentified
|
|
140
|
+
* engine never enables a capability.
|
|
141
|
+
*/
|
|
142
|
+
export const probeSmartdataEngineIdentity = async (
|
|
143
|
+
dbArg: plugins.mongodb.Db,
|
|
144
|
+
budgetArg?: SmartdataOperationBudget,
|
|
145
|
+
): Promise<ISmartdataEngineIdentity> => {
|
|
146
|
+
try {
|
|
147
|
+
return readSmartdataEngineIdentity(
|
|
148
|
+
await dbArg.command({ buildInfo: 1 }, budgetArg?.operationOptions()),
|
|
149
|
+
);
|
|
150
|
+
} catch {
|
|
151
|
+
return unidentifiedSmartdataEngine;
|
|
152
|
+
}
|
|
153
|
+
};
|
package/ts/nosqldb/index.ts
CHANGED
|
@@ -3,6 +3,17 @@ import './shim.js';
|
|
|
3
3
|
|
|
4
4
|
export { NoSqlConnection } from './classes.connection.js';
|
|
5
5
|
export type { INoSqlConnectionOptions } from './classes.connection.js';
|
|
6
|
+
export type {
|
|
7
|
+
ISmartdataEngineIdentity,
|
|
8
|
+
TSmartdataEngineBackend,
|
|
9
|
+
TSmartdataEngineProduct,
|
|
10
|
+
} from './engineidentity.js';
|
|
11
|
+
export type {
|
|
12
|
+
ICapabilities,
|
|
13
|
+
TBackend,
|
|
14
|
+
TCapability,
|
|
15
|
+
TCompositeGrouping,
|
|
16
|
+
} from '../core/interfaces.js';
|
|
6
17
|
export { nosqldbLineage } from './lineage.js';
|
|
7
18
|
export type { INosqldbLineage } from './lineage.js';
|
|
8
19
|
|
package/ts/nosqldb/lineage.ts
CHANGED
|
@@ -20,6 +20,8 @@ export const nosqldbLineage: INosqldbLineage = Object.freeze({
|
|
|
20
20
|
'classes.connection.ts adds NoSqlConnection with the client backend, capability and readiness contract.',
|
|
21
21
|
'index.ts exports NoSqlConnection, INoSqlConnectionOptions and this lineage constant.',
|
|
22
22
|
'classes.collection.ts refuses watch() when the connected backend reports change streams as unsupported.',
|
|
23
|
+
'classes.db.ts identifies the engine at init() and states the capabilities that identity implies.',
|
|
24
|
+
'classes.doc.ts refuses two-field grouped totals on a backend that does not group composite keys exactly.',
|
|
23
25
|
'The package version file is dropped; versioning belongs to @lossless.org/client.',
|
|
24
26
|
]),
|
|
25
27
|
});
|
|
@@ -26,7 +26,7 @@ export class ObjectStorageConnection extends SmartBucket {
|
|
|
26
26
|
{ forcePathStyle: options.forcePathStyle });
|
|
27
27
|
this.backend = options.backend;
|
|
28
28
|
this.capabilities = Object.freeze({ backend: this.backend, transactions: 'unsupported', changeStreams: 'unsupported',
|
|
29
|
-
objectMetrics: 'unsupported', diskResidentScans: 'unknown' });
|
|
29
|
+
compositeGrouping: 'unsupported', objectMetrics: 'unsupported', diskResidentScans: 'unknown' });
|
|
30
30
|
}
|
|
31
31
|
public async ready(options: IOperationOptions = {}): Promise<IReadiness> {
|
|
32
32
|
if (!this.options.readinessBucket) return { ready: false, reason: 'readiness_bucket_required' };
|
|
@@ -11,7 +11,8 @@ export class ClickHouseConnection {
|
|
|
11
11
|
public readonly backend = 'clickhouse' as const;
|
|
12
12
|
public readonly metrics: SmartClickHouseDb;
|
|
13
13
|
public readonly capabilities: ICapabilities = Object.freeze({ backend: 'clickhouse',
|
|
14
|
-
transactions: 'unsupported', changeStreams: 'unsupported',
|
|
14
|
+
transactions: 'unsupported', changeStreams: 'unsupported', compositeGrouping: 'unsupported',
|
|
15
|
+
objectMetrics: 'unsupported', diskResidentScans: 'available' });
|
|
15
16
|
private client?: plugins.clickhouse.ClickHouseClient;
|
|
16
17
|
private readonly operations = new Map<Operation, () => void>();
|
|
17
18
|
private readonly tasks = new Set<Promise<unknown>>();
|
|
@@ -83,7 +83,7 @@ export class SqlConnection {
|
|
|
83
83
|
}
|
|
84
84
|
this.backend = options.backend;
|
|
85
85
|
this.capabilities = Object.freeze({ backend: this.backend, transactions: 'available',
|
|
86
|
-
changeStreams: 'unsupported', objectMetrics: 'unsupported',
|
|
86
|
+
changeStreams: 'unsupported', compositeGrouping: 'unsupported', objectMetrics: 'unsupported',
|
|
87
87
|
diskResidentScans: this.backend === 'sqldb' ? 'unsupported' : 'available' });
|
|
88
88
|
}
|
|
89
89
|
|