hadron-document
Version:
Hadron Document
193 lines • 6.94 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.fieldStringLen = fieldStringLen;
exports.objectToIdiomaticEJSON = objectToIdiomaticEJSON;
exports.getDefaultValueForType = getDefaultValueForType;
exports.getDisplayType = getDisplayType;
const bson_1 = require("bson");
const hadron_type_checker_1 = __importStar(require("hadron-type-checker"));
const UNCASTED_EMPTY_TYPE_VALUE = {
Array: [],
Object: {},
Decimal128: 0,
Int32: 0,
Int64: 0,
Double: 0,
MaxKey: 0,
MinKey: 0,
Timestamp: 0,
Date: 0,
String: '',
Code: '',
Binary: '',
ObjectId: '',
BSONRegExp: '',
BSONSymbol: '',
Boolean: false,
Undefined: undefined,
Null: null,
UUID: '',
LegacyJavaUUID: '',
LegacyCSharpUUID: '',
LegacyPythonUUID: '',
};
const maxFourYearDate = new Date('9999-12-31T23:59:59.999Z').valueOf();
function fieldStringLen(value) {
const length = String(value).length;
return length === 0 ? 1 : length;
}
/**
* Turn a BSON value into what we consider idiomatic extended JSON.
*
* This differs from both the relaxed and strict mode of the 'bson'
* package's EJSON class: We preserve the type information for longs
* via $numberLong, but redact it for $numberInt and $numberDouble.
*
* This may seem inconsistent, but considering that the latter two
* types are exactly representable in JS and $numberLong is not,
* in addition to the fact that this has been historic behavior
* in Compass for a long time, this seems like a reasonable choice.
*
* Also turns $date.$numberLong into a date so that it will be
* displayed as an iso date string since this is what Compass did
* historically. Unless it is outside of the safe range.
*
* @param value Any BSON value.
* @returns A serialized, human-readable and human-editable string.
*/
function objectToIdiomaticEJSON(value, options = {}) {
const serialized = bson_1.EJSON.serialize(value, {
relaxed: false,
});
makeEJSONIdiomatic(serialized);
return JSON.stringify(serialized, null, 'indent' in options ? options.indent : 2);
}
/**
* Convert a base64 string to a UUID string (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
*/
function base64ToUUIDString(base64) {
// Decode base64 to bytes
const bytes = Buffer.from(base64, 'base64');
if (bytes.length !== 16) {
return ''; // Invalid UUID length
}
const hex = bytes.toString('hex');
// Format as UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return [
hex.substring(0, 8),
hex.substring(8, 12),
hex.substring(12, 16),
hex.substring(16, 20),
hex.substring(20, 32),
].join('-');
}
function makeEJSONIdiomatic(value) {
if (!value || typeof value !== 'object')
return;
for (const key of Object.keys(value)) {
const entry = value[key];
// We are only interested in object-like values, skip everything else
if (typeof entry !== 'object' || entry === null) {
continue;
}
if (entry.$numberInt) {
value[key] = +entry.$numberInt;
continue;
}
if (entry.$numberDouble) {
if (Number.isFinite(+entry.$numberDouble) &&
!Object.is(+entry.$numberDouble, -0)) {
// EJSON can represent +/-Infinity or NaN values but JSON can't
// (and -0 can be parsed from JSON but not serialized by JSON.stringify).
value[key] = +entry.$numberDouble;
}
continue;
}
if (entry.$date && entry.$date.$numberLong) {
const number = entry.$date.$numberLong;
if (number >= 0 && number <= maxFourYearDate) {
entry.$date = new Date(+number).toISOString();
}
}
// Convert Binary subtype 04 (UUID) to $uuid format for better readability
if (entry.$binary &&
entry.$binary.subType === '04' &&
entry.$binary.base64) {
const uuidString = base64ToUUIDString(entry.$binary.base64);
if (uuidString) {
value[key] = { $uuid: uuidString };
continue;
}
}
makeEJSONIdiomatic(entry);
}
}
/**
* Returns a default value for the BSON type passed in.
*/
function getDefaultValueForType(type) {
return hadron_type_checker_1.default.cast(UNCASTED_EMPTY_TYPE_VALUE[type], type);
}
/**
* Gets the display type for an element, considering legacy UUID encoding
* preference.
*
* - For Binary subtype 3 (legacy UUID), returns the appropriate legacy UUID
* type based on context.
* - For Binary subtype 4 (UUID), returns 'UUID'.
* - For all other types, returns the element's currentType.
*/
function getDisplayType(el, legacyUUIDEncoding) {
// If the element already has a specific UUID type, use it
if ((0, hadron_type_checker_1.isUUIDType)(el.currentType)) {
return el.currentType;
}
// Check if this is a Binary that should be displayed as a UUID type
if (el.currentType === 'Binary' &&
(0, hadron_type_checker_1.getBsonType)(el.currentValue) === 'Binary') {
const binary = el.currentValue;
if (binary.sub_type === bson_1.Binary.SUBTYPE_UUID) {
return 'UUID';
}
if (binary.sub_type === bson_1.Binary.SUBTYPE_UUID_OLD &&
binary.buffer.length === 16 &&
legacyUUIDEncoding) {
return legacyUUIDEncoding;
}
}
return el.currentType;
}
//# sourceMappingURL=utils.js.map