@datastax/astra-db-ts
Version:
Data API TypeScript client
229 lines (228 loc) • 9.25 kB
JavaScript
;
// Copyright Datastax, Inc
// SPDX-License-Identifier: Apache-2.0
Object.defineProperty(exports, "__esModule", { value: true });
exports.TableSerDes = void 0;
const ser_des_js_1 = require("../../../lib/api/ser-des/ser-des.js");
const codecs_js_1 = require("../../../documents/tables/ser-des/codecs.js");
const ctx_js_1 = require("../../../lib/api/ser-des/ctx.js");
const constants_js_1 = require("../../../documents/tables/ser-des/constants.js");
const utils_js_1 = require("../../../lib/utils.js");
const index_js_1 = require("../../../client/index.js");
const cfg_handler_js_1 = require("../../../documents/tables/ser-des/cfg-handler.js");
const utils_js_2 = require("../../../lib/api/ser-des/utils.js");
class TableSerDes extends ser_des_js_1.SerDes {
constructor(cfg) {
super(TableSerDes.cfg.concat([codecs, cfg]), serialize, deserialize);
}
adaptSerCtx(ctx) {
ctx.bigNumsPresent = false;
return ctx;
}
adaptDesCtx(ctx) {
const rawDataApiResp = ctx.rawDataApiResp;
const status = index_js_1.UnexpectedDataAPIResponseError.require(rawDataApiResp.status, 'No `status` found in response.', rawDataApiResp);
if (ctx.target === ctx_js_1.SerDesTarget.InsertedId) {
ctx.tableSchema = index_js_1.UnexpectedDataAPIResponseError.require(status.primaryKeySchema, 'No `status.primaryKeySchema` found in response.\n\n**Did you accidentally use a `Table` object on a Collection?** If so, your document was successfully inserted, but the client cannot properly deserialize the response. Please use a `Collection` object instead.', rawDataApiResp);
}
else {
ctx.tableSchema = index_js_1.UnexpectedDataAPIResponseError.require(status.projectionSchema, 'No `status.projectionSchema` found in response.\n\n**Did you accidentally use a `Table` object on a Collection?** If so, documents may\'ve been found, but the client cannot properly deserialize the response. Please use a `Collection` object instead.', rawDataApiResp);
}
if (ctx.target === ctx_js_1.SerDesTarget.InsertedId) {
ctx.rootObj = Object.fromEntries(Object.keys(ctx.tableSchema).map((key, i) => {
return [key, ctx.rootObj[i]];
}));
}
if (this._cfg.sparseData !== true) {
populateSparseData(ctx);
}
return ctx;
}
bigNumsPresent(ctx) {
return ctx.bigNumsPresent;
}
}
exports.TableSerDes = TableSerDes;
Object.defineProperty(TableSerDes, "cfg", {
enumerable: true,
configurable: true,
writable: true,
value: cfg_handler_js_1.TableSerDesCfgHandler
});
const serialize = (value, ctx) => {
let resp = null;
// Path-based serializers
for (const pathSer of ctx.serializers.forPath[ctx.path.length] ?? []) {
if ((0, utils_js_2.pathMatches)(pathSer.path, ctx.path) && pathSer.fns.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
}
// Name-based serializers
const key = ctx.path[ctx.path.length - 1] ?? '';
const nameSer = ctx.serializers.forName[key];
if (nameSer?.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
// Type-based & custom serializers
for (const guardSer of ctx.serializers.forGuard) {
if (guardSer.guard(value, ctx) && (resp = guardSer.fn(value, ctx))[0] !== ctx_js_1.NEVERMIND) {
return resp;
}
}
if (typeof value === 'number') {
if (!isFinite(value)) {
return ctx.done(value.toString());
}
}
else if (typeof value === 'object' && value !== null) {
// Delegate serializer
if (value[constants_js_1.$SerializeForTable] && (resp = value[constants_js_1.$SerializeForTable](ctx))[0] !== ctx_js_1.NEVERMIND) {
return resp;
}
// Class-based serializers
const classSer = ctx.serializers.forClass.find((c) => value instanceof c.class);
if (classSer?.fns.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
// Enable using json-bigint
if ((0, utils_js_1.isBigNumber)(value)) {
ctx.bigNumsPresent = true;
return ctx.done();
}
}
else if (typeof value === 'bigint') {
ctx.bigNumsPresent = true;
}
return ctx.recurse();
};
const deserialize = (value, ctx) => {
let resp = null;
// Path-based deserializers
for (const pathDes of ctx.deserializers.forPath[ctx.path.length] ?? []) {
if ((0, utils_js_2.pathMatches)(pathDes.path, ctx.path) && pathDes.fns.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
}
// Name-based deserializers
const key = ctx.path[ctx.path.length - 1] ?? '';
const nameDes = ctx.deserializers.forName[key];
if (nameDes?.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
// Custom deserializers
for (const guardDes of ctx.deserializers.forGuard) {
if (guardDes.guard(value, ctx) && (resp = guardDes.fn(value, ctx))[0] !== ctx_js_1.NEVERMIND) {
return resp;
}
}
if (ctx.path.length === 0 || value === null) {
return ctx.recurse(value);
}
// Type-based deserializers
const type = resolveAbsType(value, ctx);
const typeDes = type && ctx.deserializers.forType[type];
if (typeDes && typeDes.find((fns) => (resp = fns(value, ctx))[0] !== ctx_js_1.NEVERMIND)) {
return resp;
}
return ctx.recurse(value);
};
const codecs = TableSerDes.cfg.parse({ codecs: Object.values(codecs_js_1.TableCodecs.Defaults) });
function populateSparseData(ctx) {
var _a;
for (const col in ctx.tableSchema) {
const colIsPresent = Object.prototype.hasOwnProperty.call(ctx.rootObj, col);
const typeDef = ctx.tableSchema[col]; // typeDef and type are linked, but we can't represent that in the type system :/
const type = resolveType(typeDef);
switch (type) {
case 'map':
if (!colIsPresent) {
ctx.rootObj[col] = {};
}
else if (typeof typeDef === 'object' && typeDef.valueType.type === 'userDefined') {
const value = ctx.rootObj[col];
if (Array.isArray(value)) {
for (const kv of value) {
populateSparseUdt(kv[1], typeDef.valueType.definition);
}
}
else {
for (const v of Object.values(value)) {
populateSparseUdt(v, typeDef.valueType.definition);
}
}
}
break;
case 'set':
case 'list':
if (!colIsPresent) {
ctx.rootObj[col] = [];
}
else if (typeof typeDef === 'object' && typeDef.valueType.type === 'userDefined') {
ctx.rootObj[col].forEach((obj) => populateSparseUdt(obj, typeDef.valueType.definition));
}
break;
case 'userDefined':
(_a = ctx.rootObj)[col] ?? (_a[col] = {});
populateSparseUdt(ctx.rootObj[col], typeDef.definition);
break;
default:
if (!colIsPresent) {
ctx.rootObj[col] = null;
}
}
}
}
function populateSparseUdt(obj, def) {
for (const col in def.fields) {
if (!Object.prototype.hasOwnProperty.call(obj, col)) {
obj[col] = null;
}
}
}
function resolveAbsType(value, { path, tableSchema }) {
let typeDef = tableSchema[path[0]];
if (!typeDef)
return undefined;
let type = resolveType(typeDef);
let depth = 1;
while (depth < path.length && typeDef) {
switch (type) {
case 'map':
if (path[depth + 1] === undefined) {
return (!Array.isArray(value))
? typeDef.valueType
: undefined;
}
typeDef = (path[depth + 1] === 0)
? typeDef.keyType
: typeDef.valueType;
type = resolveType(typeDef);
depth += 2;
break;
case 'list':
case 'set':
typeDef = typeDef.valueType;
type = resolveType(typeDef);
depth++;
break;
case 'userDefined':
typeDef = typeDef.definition.fields[path[depth]];
if (!typeDef)
return undefined;
type = resolveType(typeDef);
depth++;
break;
default:
return type;
}
}
return type;
}
function resolveType(column) {
if (typeof column === 'string') {
return column;
}
return (column.type === 'UNSUPPORTED')
? column.apiSupport.cqlDefinition
: column.type;
}