opusdev/vector-similarity-api
1
1import { Binary } from '../binary';2import type { Document } from '../bson';3import { BSONError, BSONVersionError } from '../error';4import * as constants from '../constants';5import { ByteUtils } from '../utils/byte_utils';6import { isAnyArrayBuffer, isDate, isRegExp } from './utils';7 8export function internalCalculateObjectSize(9 object: Document,10 serializeFunctions?: boolean,11 ignoreUndefined?: boolean12): number {13 let totalLength = 4 + 1;14 15 if (Array.isArray(object)) {16 for (let i = 0; i < object.length; i++) {17 totalLength += calculateElement(18 i.toString(),19 object[i],20 serializeFunctions,21 true,22 ignoreUndefined23 );24 }25 } else {26 // If we have toBSON defined, override the current object27 28 if (typeof object?.toBSON === 'function') {29 object = object.toBSON();30 }31 32 // Calculate size33 for (const key of Object.keys(object)) {34 totalLength += calculateElement(key, object[key], serializeFunctions, false, ignoreUndefined);35 }36 }37 38 return totalLength;39}40 41/** @internal */42function calculateElement(43 name: string,44 // eslint-disable-next-line @typescript-eslint/no-explicit-any45 value: any,46 serializeFunctions = false,47 isArray = false,48 ignoreUndefined = false49) {50 // If we have toBSON defined, override the current object51 if (typeof value?.toBSON === 'function') {52 value = value.toBSON();53 }54 55 switch (typeof value) {56 case 'string':57 return 1 + ByteUtils.utf8ByteLength(name) + 1 + 4 + ByteUtils.utf8ByteLength(value) + 1;58 case 'number':59 if (60 Math.floor(value) === value &&61 value >= constants.JS_INT_MIN &&62 value <= constants.JS_INT_MAX63 ) {64 if (value >= constants.BSON_INT32_MIN && value <= constants.BSON_INT32_MAX) {65 // 32 bit66 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (4 + 1);67 } else {68 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);69 }70 } else {71 // 64 bit72 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);73 }74 case 'undefined':75 if (isArray || !ignoreUndefined)76 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + 1;77 return 0;78 case 'boolean':79 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (1 + 1);80 case 'object':81 if (82 value != null &&83 typeof value._bsontype === 'string' &&84 value[constants.BSON_VERSION_SYMBOL] !== constants.BSON_MAJOR_VERSION85 ) {86 throw new BSONVersionError();87 } else if (value == null || value._bsontype === 'MinKey' || value._bsontype === 'MaxKey') {88 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + 1;89 } else if (value._bsontype === 'ObjectId') {90 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (12 + 1);91 } else if (value instanceof Date || isDate(value)) {92 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);93 } else if (94 ArrayBuffer.isView(value) ||95 value instanceof ArrayBuffer ||96 isAnyArrayBuffer(value)97 ) {98 return (99 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (1 + 4 + 1) + value.byteLength100 );101 } else if (102 value._bsontype === 'Long' ||103 value._bsontype === 'Double' ||104 value._bsontype === 'Timestamp'105 ) {106 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);107 } else if (value._bsontype === 'Decimal128') {108 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (16 + 1);109 } else if (value._bsontype === 'Code') {110 // Calculate size depending on the availability of a scope111 if (value.scope != null && Object.keys(value.scope).length > 0) {112 return (113 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +114 1 +115 4 +116 4 +117 ByteUtils.utf8ByteLength(value.code.toString()) +118 1 +119 internalCalculateObjectSize(value.scope, serializeFunctions, ignoreUndefined)120 );121 } else {122 return (123 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +124 1 +125 4 +126 ByteUtils.utf8ByteLength(value.code.toString()) +127 1128 );129 }130 } else if (value._bsontype === 'Binary') {131 const binary: Binary = value;132 // Check what kind of subtype we have133 if (binary.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {134 return (135 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +136 (binary.position + 1 + 4 + 1 + 4)137 );138 } else {139 return (140 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (binary.position + 1 + 4 + 1)141 );142 }143 } else if (value._bsontype === 'Symbol') {144 return (145 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +146 ByteUtils.utf8ByteLength(value.value) +147 4 +148 1 +149 1150 );151 } else if (value._bsontype === 'DBRef') {152 // Set up correct object for serialization153 const ordered_values = Object.assign(154 {155 $ref: value.collection,156 $id: value.oid157 },158 value.fields159 );160 161 // Add db reference if it exists162 if (value.db != null) {163 ordered_values['$db'] = value.db;164 }165 166 return (167 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +168 1 +169 internalCalculateObjectSize(ordered_values, serializeFunctions, ignoreUndefined)170 );171 } else if (value instanceof RegExp || isRegExp(value)) {172 return (173 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +174 1 +175 ByteUtils.utf8ByteLength(value.source) +176 1 +177 (value.global ? 1 : 0) +178 (value.ignoreCase ? 1 : 0) +179 (value.multiline ? 1 : 0) +180 1181 );182 } else if (value._bsontype === 'BSONRegExp') {183 return (184 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +185 1 +186 ByteUtils.utf8ByteLength(value.pattern) +187 1 +188 ByteUtils.utf8ByteLength(value.options) +189 1190 );191 } else {192 return (193 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +194 internalCalculateObjectSize(value, serializeFunctions, ignoreUndefined) +195 1196 );197 }198 case 'function':199 if (serializeFunctions) {200 return (201 (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) +202 1 +203 4 +204 ByteUtils.utf8ByteLength(value.toString()) +205 1206 );207 }208 return 0;209 case 'bigint':210 return (name != null ? ByteUtils.utf8ByteLength(name) + 1 : 0) + (8 + 1);211 case 'symbol':212 return 0;213 default:214 throw new BSONError(`Unrecognized JS type: ${typeof value}`);215 }216 217 return 0;218}219 