@datastax/astra-db-ts
Version:
Data API TypeScript client
206 lines (205 loc) • 9.56 kB
JavaScript
;
// Copyright Datastax, Inc
// SPDX-License-Identifier: Apache-2.0
// noinspection ExceptionCaughtLocallyJS
var _DataAPIHttpClient_props;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataAPIHttpClient = exports.EmissionStrategy = void 0;
const tslib_1 = require("tslib");
const index_js_1 = require("../../../lib/index.js");
const index_js_2 = require("../../../documents/index.js");
const http_client_js_1 = require("../../../lib/api/clients/http-client.js");
const constants_js_1 = require("../../../lib/api/constants.js");
const timeouts_js_1 = require("../../../lib/api/timeouts/timeouts.js");
const errors_js_1 = require("../../../lib/errors.js");
const utils_js_1 = require("../../../lib/utils.js");
exports.EmissionStrategy = {
Normal: (logger) => ({
emitCommandStarted(reqId, info, opts) {
logger.commandStarted?.(reqId, info, opts.extraLogInfo);
},
emitCommandFailed(reqId, info, resp, error, started, opts) {
logger.commandFailed?.(reqId, info, opts.extraLogInfo, resp, error, started);
},
emitCommandSucceeded(reqId, info, resp, started, opts) {
logger.commandSucceeded?.(reqId, info, opts.extraLogInfo, resp, started);
},
emitCommandWarnings(reqId, info, warnings, opts) {
logger.commandWarnings?.(reqId, info, opts.extraLogInfo, warnings);
},
}),
Admin: (logger) => ({
emitCommandStarted(reqId, info, opts) {
logger.adminCommandStarted?.(reqId, '', adaptInfo4Devops(info, opts.methodName), true, null); // TODO
},
emitCommandFailed(reqId, info, _, error, started, opts) {
logger.adminCommandFailed?.(reqId, '', adaptInfo4Devops(info, opts.methodName), true, error, started);
},
emitCommandSucceeded(reqId, info, resp, started, opts) {
logger.adminCommandSucceeded?.(reqId, '', adaptInfo4Devops(info, opts.methodName), true, resp, started);
},
emitCommandWarnings(reqId, info, warnings, opts) {
logger.adminCommandWarnings?.(reqId, '', adaptInfo4Devops(info, opts.methodName), true, warnings);
},
}),
};
const adaptInfo4Devops = (info, methodName) => ({
method: 'POST',
data: info.command,
path: info.url,
methodName,
});
class DataAPIHttpClient extends http_client_js_1.HttpClient {
constructor(opts) {
super('data-api', {
...opts,
additionalHeaders: index_js_1.HeadersProvider.opts.fromObj.concat([
opts.additionalHeaders,
opts.tokenProvider.toHeadersProvider(),
]),
mkTimeoutError: index_js_2.DataAPITimeoutError.mk,
});
Object.defineProperty(this, "collectionName", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "tableName", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "keyspace", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "emissionStrategy", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "bigNumHack", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
_DataAPIHttpClient_props.set(this, void 0);
this.keyspace = opts.keyspace;
tslib_1.__classPrivateFieldSet(this, _DataAPIHttpClient_props, opts, "f");
this.emissionStrategy = opts.emissionStrategy(opts.logger.internal);
}
forTableSlashCollectionOrWhateverWeWouldCallTheUnionOfTheseTypes(tSlashC, opts, bigNumHack) {
const clone = new DataAPIHttpClient({
...tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f"),
emissionStrategy: exports.EmissionStrategy.Normal,
keyspace: { ref: tSlashC.keyspace },
logger: tSlashC,
additionalHeaders: index_js_1.HeadersProvider.opts.monoid.concat([
tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f").additionalHeaders,
index_js_1.HeadersProvider.opts.fromStr(index_js_1.EmbeddingAPIKeyHeaderProvider).parse(opts?.embeddingApiKey),
index_js_1.HeadersProvider.opts.fromStr(index_js_1.RerankingAPIKeyHeaderProvider).parse(opts?.rerankingApiKey),
]),
});
if (tSlashC instanceof index_js_2.Collection) {
clone.collectionName = tSlashC.name;
}
else {
clone.tableName = tSlashC.name;
}
clone.bigNumHack = bigNumHack;
clone.tm = new timeouts_js_1.Timeouts(index_js_2.DataAPITimeoutError.mk, timeouts_js_1.Timeouts.cfg.parse({ ...this.tm.baseTimeouts, ...opts?.timeoutDefaults }));
return clone;
}
forDbAdmin(dbAdmin, opts) {
const clone = new DataAPIHttpClient({
...tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f"),
tokenProvider: index_js_1.TokenProvider.opts.concat([opts.adminToken, tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f").tokenProvider]),
baseUrl: opts?.endpointUrl ?? tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f").baseUrl,
baseApiPath: opts?.endpointUrl ? '' : tslib_1.__classPrivateFieldGet(this, _DataAPIHttpClient_props, "f").baseApiPath,
emissionStrategy: exports.EmissionStrategy.Admin,
logger: dbAdmin,
});
clone.collectionName = undefined;
clone.tableName = undefined;
clone.tm = new timeouts_js_1.Timeouts(index_js_2.DataAPITimeoutError.mk, { ...this.tm.baseTimeouts, ...opts?.timeoutDefaults });
return clone;
}
async executeCommand(command, options) {
if (options?.collection && options.table) {
throw new Error('Can\'t provide both `table` and `collection` as options to DataAPIHttpClient.executeCommand()');
}
const tOrC = options.collection || options.table || this.collectionName || this.tableName;
const keyspace = options.keyspace === undefined ? this.keyspace?.ref : options.keyspace;
if (keyspace === undefined) {
throw new Error('Db is missing a required keyspace; be sure to set one with client.db(..., { keyspace }), or db.useKeyspace()');
}
if (keyspace === null && tOrC) {
throw new Error('Keyspace may not be `null` when a table or collection is provided to DataAPIHttpClient.executeCommand()');
}
const info = {
url: this.baseUrl,
tOrC: tOrC,
tOrCType: !tOrC ? undefined : tOrC === (options.table || this.tableName) ? 'table' : 'collection',
keyspace: keyspace,
command: command,
timeoutManager: options.timeoutManager,
bigNumsPresent: options.bigNumsPresent,
};
const keyspacePath = info.keyspace ? `/${info.keyspace}` : '';
const collectionPath = info.tOrC ? `/${info.tOrC}` : '';
info.url += keyspacePath + collectionPath;
const requestId = this.logger.internal.generateCommandRequestId();
this.emissionStrategy.emitCommandStarted?.(requestId, info, options);
const started = performance.now();
let clonedData;
try {
const serialized = (info.bigNumsPresent)
? this.bigNumHack?.parser.stringify(info.command)
: JSON.stringify(info.command);
const resp = await this._request({
url: info.url,
data: serialized,
timeoutManager: info.timeoutManager,
method: constants_js_1.HttpMethods.Post,
});
if (resp.status >= 400 && resp.status !== 401) {
throw new index_js_2.DataAPIHttpError(resp);
}
const data = (resp.body)
? (this.bigNumHack?.parseWithBigNumbers(resp.body))
? this.bigNumHack?.parser.parse(resp.body)
: JSON.parse(resp.body)
: {};
clonedData = requestId
? structuredClone(data)
: undefined;
const warnings = data?.status?.warnings ?? [];
if (warnings.length) {
this.emissionStrategy.emitCommandWarnings?.(requestId, info, warnings, options);
}
if (data.errors && (0, utils_js_1.isNonEmpty)(data.errors)) {
throw new index_js_2.DataAPIResponseError(info.command, data);
}
const respData = {
data: data.data,
status: data.status,
errors: data.errors,
};
this.emissionStrategy.emitCommandSucceeded?.(requestId, info, clonedData, started, options);
return respData;
}
catch (thrown) {
const err = errors_js_1.NonErrorError.asError(thrown);
this.emissionStrategy.emitCommandFailed?.(requestId, info, clonedData, err, started, options);
throw err;
}
}
}
exports.DataAPIHttpClient = DataAPIHttpClient;
_DataAPIHttpClient_props = new WeakMap();