@datastax/astra-db-ts
Version:
Data API TypeScript client
126 lines (125 loc) • 4.19 kB
JavaScript
// Copyright Datastax, Inc
// SPDX-License-Identifier: Apache-2.0
import { ctxDone, ctxNevermind, ctxRecurse, ctxReplace, DONE, NEVERMIND, REPLACE, SerDesTarget, } from '../../../lib/api/ser-des/ctx.js';
import { processCodecs } from '../../../lib/api/ser-des/codecs.js';
export class SerDes {
constructor(_cfg, _serialize, _deserialize) {
Object.defineProperty(this, "_cfg", {
enumerable: true,
configurable: true,
writable: true,
value: _cfg
});
Object.defineProperty(this, "_serialize", {
enumerable: true,
configurable: true,
writable: true,
value: _serialize
});
Object.defineProperty(this, "_deserialize", {
enumerable: true,
configurable: true,
writable: true,
value: _deserialize
});
Object.defineProperty(this, "_serializers", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_deserializers", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
[this._serializers, this._deserializers] = processCodecs(this._cfg.codecs.flat());
}
serialize(obj, target = SerDesTarget.Record) {
if (obj === null || obj === undefined) {
return [obj, false];
}
const ctx = this.adaptSerCtx(this._mkCtx(obj, target, {
mutatingInPlace: this._cfg.mutateInPlace === true,
serializers: this._serializers,
}));
const serialized = serdesRecord('', { ['']: ctx.rootObj }, ctx, this._serialize)[''];
return [serialized, this.bigNumsPresent(ctx)];
}
deserialize(obj, raw, target = SerDesTarget.Record) {
if (obj === null || obj === undefined) {
return obj;
}
const ctx = this.adaptDesCtx(this._mkCtx(obj, target, {
deserializers: this._deserializers,
rawDataApiResp: raw,
}));
return serdesRecord('', { ['']: ctx.rootObj }, ctx, this._deserialize)[''];
}
_mkCtx(obj, target, ctx) {
return {
done: ctxDone,
recurse: ctxRecurse,
nevermind: ctxNevermind,
replace: ctxReplace,
mutatingInPlace: true,
mapAfter: null,
target: target,
rootObj: obj,
path: [],
locals: {},
...ctx,
};
}
}
function serdesRecord(key, obj, ctx, fn) {
const postMaps = [];
ctx.mapAfter = (fn) => { postMaps.push(fn); return [NEVERMIND]; };
const stop = applySerdesFn(fn, key, obj, ctx);
if (ctx.path.length >= 250) {
throw new Error('Tried to ser/des a document with a depth of over 250. Did you accidentally create a circular reference?');
}
if (!stop && typeof obj[key] === 'object' && obj[key] !== null) {
obj[key] = serdesRecordHelper(obj[key], ctx, fn);
}
for (let i = postMaps.length - 1; i >= 0; i--) {
obj[key] = postMaps[i](obj[key]);
}
return obj;
}
function serdesRecordHelper(obj, ctx, fn) {
obj = (!ctx.mutatingInPlace)
? (Array.isArray(obj) ? [...obj] : { ...obj })
: obj;
const path = ctx.path;
path.push('<temp>');
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
path[path.length - 1] = i;
serdesRecord(i, obj, ctx, fn);
}
}
else {
for (const key of Object.keys(obj)) {
path[path.length - 1] = key;
serdesRecord(key, obj, ctx, fn);
}
}
path.pop();
return obj;
}
function applySerdesFn(fn, key, obj, ctx) {
let res = null;
let loops = 0;
do {
res = fn(obj[key], ctx);
if (res.length === 2) {
obj[key] = res[1];
}
if (loops++ > 250) {
throw new Error('Potential infinite loop caused by ctx.replaces detected (>250 iterations)');
}
} while (res[0] === REPLACE);
return res[0] === DONE;
}