UNPKG

@datastax/astra-db-ts

Version:
126 lines (125 loc) 4.19 kB
// 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; }