UNPKG

@datastax/astra-mongoose

Version:

Astra's NodeJS Mongoose compatibility client

263 lines 11.5 kB
"use strict"; // Copyright DataStax, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = convertSchemaToColumns; const astraMongooseError_1 = require("./astraMongooseError"); const getUDTNameFromSchemaType_1 = __importDefault(require("./udt/getUDTNameFromSchemaType")); /** * Given a Mongoose schema, create an equivalent Data API table definition for use with `createTable()` */ function convertSchemaToColumns(schema, udtName) { const versionKey = schema.options.versionKey; const columns = {}; if (schema.options._id !== false) { columns._id = { type: 'text' }; } if (typeof versionKey === 'string') { columns[versionKey] = { type: 'int' }; } const schemaTypesForNestedPath = {}; udtName = udtName ?? schema.options?.udtName; for (const path of Object.keys(schema.paths)) { const schemaType = schema.paths[path]; const type = mongooseTypeToDataAPIType(schemaType.instance); const isNestedOrMap = path.indexOf('.') !== -1; if (isNestedOrMap) { const split = schemaType.path.split('.'); if (split.length > 2) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: schemas with paths that are more than 2 levels deep are not supported (found ${path})`, { path, type, schema }); } // Nested paths aren't listed in `schema.paths`, so store their subpaths to process them later on a // per-nested-path basis. if (schema.pathType(split[0]) === 'nested') { const nestedPath = split[0]; if (schemaTypesForNestedPath[nestedPath] == null) { schemaTypesForNestedPath[nestedPath] = []; } schemaTypesForNestedPath[nestedPath].push(schemaType); } } else if (type) { columns[path] = { type }; } else if (schemaType.instance === 'Array' || schemaType.instance === 'Vectorize') { if (udtName != null) { throw new astraMongooseError_1.AstraMongooseError('Cannot convert schema to Data API table definition: cannot store an array in a UDT', { path, type }); } if (schemaType.schema) { // If `schema` is set, this is a DocumentArray const schemaTypeUDTName = (0, getUDTNameFromSchemaType_1.default)(schemaType); if (schemaTypeUDTName) { columns[path] = { type: 'list', valueType: { type: 'userDefined', udtName: schemaTypeUDTName } }; } else { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: DocumentArray "${path}" is not supported`, { path, type, schema }); } } else { // Arrays always have an embedded schema type const embeddedSchemaType = schemaType.getEmbeddedSchemaType(); if (schemaType.options.dimension != null) { // If dimension, assume we're creating a vector column if (embeddedSchemaType.instance !== 'Number') { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: vector column at "${path}" must be an array of numbers`, { path, type, schema }); } columns[path] = { type: 'vector', dimension: schemaType.options.dimension }; if (schemaType.instance === 'Vectorize' && schemaType.options.service != null) { columns[path].service = schemaType.options.service; } } else { const valueType = mongooseTypeToDataAPIType(embeddedSchemaType.instance); if (valueType == null) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: unsupported array type at path "${path}"`, { path, valueType, type, schema }); } columns[path] = { type: 'list', valueType }; } } } else if (schemaType.instance === 'Embedded') { if (udtName != null) { throw new astraMongooseError_1.AstraMongooseError('Cannot convert schema to Data API table definition: cannot store a subdocument in a UDT', { path, type }); } const schemaTypeUDTName = (0, getUDTNameFromSchemaType_1.default)(schemaType); if (schemaTypeUDTName) { columns[path] = { type: 'userDefined', udtName: schemaTypeUDTName }; } else { columns[path] = { type: 'map', keyType: 'text', valueType: getValueTypeFromNestedSchemaTypes(path, Object.values(schemaType.schema.paths), true) }; } } else if (schemaType.instance === 'Map') { if (udtName != null) { throw new astraMongooseError_1.AstraMongooseError('Cannot convert schema to Data API table definition: cannot store a map in a UDT', { path, type }); } const embeddedSchemaType = schemaType.getEmbeddedSchemaType(); if (!isSchemaTypeRequired(embeddedSchemaType)) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: values for map path "${path}" must be required`, { path, type }); } const valueType = mongooseTypeToDataAPIType(embeddedSchemaType.instance); const schemaTypeUDTName = (0, getUDTNameFromSchemaType_1.default)(schemaType); if (valueType != null) { columns[path] = { type: 'map', keyType: 'text', valueType }; } else if (schemaTypeUDTName) { // Special handling for maps of UDTs columns[path] = { type: 'map', keyType: 'text', valueType: { type: 'userDefined', udtName: schemaTypeUDTName } }; } else { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: unsupported type at path "${schemaType.path}"`, { path, type }); } } else { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: unsupported type at path "${path}"`, { path, schema }); } } for (const nestedPath of Object.keys(schemaTypesForNestedPath)) { columns[nestedPath] = { type: 'map', keyType: 'text', valueType: getValueTypeFromNestedSchemaTypes(nestedPath, schemaTypesForNestedPath[nestedPath], false) }; } return columns; } function getValueTypeFromNestedSchemaTypes(nestedPath, schemaTypes, isSubdocument) { const dataAPITypes = new Set(); for (const schemaType of schemaTypes) { const hasNested = schemaType.path.indexOf('.') !== -1; if (hasNested && isSubdocument) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: unsupported nested path underneath subdocument at path "${nestedPath}.${schemaType.path}"`, { nestedPath }); } const type = mongooseTypeToDataAPIType(schemaType.instance); const fullPath = isSubdocument ? `${nestedPath}.${schemaType.path}` : schemaType.path; if (type == null) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: unsupported type at path "${fullPath}"`, { nestedPath, type }); } if (!isSchemaTypeRequired(schemaType)) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: nested path "${fullPath}" must be required`, { nestedPath, type }); } dataAPITypes.add(type); } if (dataAPITypes.has('blob')) { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: nested Buffer at "${nestedPath}" is not supported`, { nestedPath }); } // If all keys have same data type, then we can use that data type if (dataAPITypes.size === 1) { return Array.from(dataAPITypes)[0]; } else { throw new astraMongooseError_1.AstraMongooseError(`Cannot convert schema to Data API table definition: nested paths with different data types "${nestedPath}" are not supported`, { nestedPath }); } } function mongooseTypeToDataAPIType(type) { if (type === 'String') { return 'text'; } else if (type === 'Number') { return 'double'; } else if (type === 'Date') { return 'timestamp'; } else if (type === 'Boolean') { return 'boolean'; } else if (type === 'Decimal128') { return 'decimal'; } else if (type === 'BigInt') { return 'varint'; } else if (type === 'Buffer') { return 'blob'; } else if (type === 'ObjectId') { return 'text'; } else if (type === 'UUID') { return 'uuid'; } else if (type === 'Int32') { return 'int'; } else if (type === 'Double') { return 'double'; } return null; } function isSchemaTypeRequired(schemaType) { const requiredOption = schemaType.options.required; if (typeof requiredOption === 'boolean') { return requiredOption; } if (typeof requiredOption === 'function') { return false; } if (Array.isArray(requiredOption)) { return requiredOption[0]; } return false; } //# sourceMappingURL=convertSchemaToColumns.js.map