@datastax/astra-mongoose
Version:
Astra's NodeJS Mongoose compatibility client
236 lines • 10.1 kB
JavaScript
;
// 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.TablesDb = exports.CollectionsDb = exports.BaseDb = void 0;
const astraMongooseError_1 = require("../astraMongooseError");
const assert_1 = __importDefault(require("assert"));
/**
* Defines the base database class for interacting with Astra DB. Responsible for creating collections and tables.
* This class abstracts the operations for both collections mode and tables mode. There is a separate TablesDb class
* for tables and CollectionsDb class for collections.
*/
class BaseDb {
constructor(astraDb, keyspaceName, isTable) {
this.astraDb = astraDb;
astraDb.useKeyspace(keyspaceName);
this.isTable = !!isTable;
this.name = keyspaceName;
}
/**
* Create a new table with the specified name and definition
* @param name
* @param definition
*/
async createTable(name, definition, options) {
return await this.astraDb.createTable(name, { ...options, definition });
}
/**
* Drop a collection by name.
* @param name The name of the collection to be dropped.
*/
async dropCollection(name, options) {
return await this.astraDb.dropCollection(name, options);
}
/**
* Drop a table by name. This function does **not** throw an error if the table does not exist.
* @param name
*/
async dropTable(name, options) {
return await this.astraDb.dropTable(name, {
ifExists: true,
...options
});
}
async listCollections(options) {
if (options?.nameOnly) {
return await this.astraDb.listCollections({ ...options, nameOnly: true });
}
return await this.astraDb.listCollections({ ...options, nameOnly: false });
}
async listTables(options) {
if (options?.nameOnly) {
return await this.astraDb.listTables({ ...options, nameOnly: true });
}
return await this.astraDb.listTables({ ...options, nameOnly: false });
}
async listTypes(options) {
if (options?.nameOnly) {
return await this.astraDb.listTypes({ ...options, nameOnly: true });
}
return await this.astraDb.listTypes({ ...options, nameOnly: false });
}
/**
* Create a new user-defined type (UDT) with the specified name and fields definition.
* @param name The name of the type to create.
* @param definition The definition of the fields for the type.
* @returns The result of the createType command.
*/
async createType(name, definition) {
return await this.astraDb.createType(name, { definition });
}
/**
* Drop (delete) a user-defined type (UDT) by name.
* @param name The name of the type to drop.
* @returns The result of the dropType command.
*/
async dropType(name, options) {
return await this.astraDb.dropType(name, options);
}
/**
* Alter a user-defined type (UDT) by renaming or adding fields.
* @param name The name of the type to alter.
* @param update The alterations to be made: renaming or adding fields.
* @returns The result of the alterType command.
*/
async alterType(name, update) {
return await this.astraDb.alterType(name, update);
}
/**
* Synchronizes the set of user-defined types (UDTs) in the database. It makes existing types in the database
* match the list provided by `types`. New types that are missing are created, and types that exist in the database
* but are not in the input list are dropped. If a type is present in both, we add all the new type's fields to the existing type.
*
* @param types An array of objects each specifying the name and CreateTypeDefinition for a UDT to synchronize.
* @returns An object describing which types were created, updated, or dropped.
* @throws {AstraMongooseError} If an error occurs during type synchronization, with partial progress information in the error.
*/
async syncTypes(types) {
const existingTypes = await this.listTypes({ nameOnly: false });
const existingTypeNames = existingTypes.map(type => type.name);
const inputTypeNames = types.map(type => type.name);
const toCreate = types
.filter(type => !existingTypeNames.includes(type.name))
.map(type => type.name);
const toUpdate = types
.filter(type => existingTypeNames.includes(type.name))
.map(type => type.name);
const toDrop = existingTypeNames.filter(typeName => !inputTypeNames.includes(typeName));
// We'll perform these in series and track progress
const created = [];
const updated = [];
const dropped = [];
try {
for (const type of types) {
if (toCreate.includes(type.name)) {
await this.createType(type.name, type.definition);
created.push(type.name);
}
}
for (const typeName of toDrop) {
await this.dropType(typeName);
dropped.push(typeName);
}
for (const type of types) {
if (toUpdate.includes(type.name)) {
const existingType = existingTypes.find(t => t.name === type.name);
// This cannot happen, but add a guard for TypeScript
assert_1.default.ok(existingType);
const existingFields = existingType.definition.fields;
const fieldsToAdd = { fields: {} };
for (const [field, newField] of Object.entries(type.definition.fields)) {
if (existingFields?.[field] != null) {
const existingFieldType = existingFields[field];
// Compare type as string since Astra DB types may be represented in string form
const newFieldType = typeof newField === 'string' ? newField : newField.type;
if (existingFieldType.type !== newFieldType) {
throw new astraMongooseError_1.AstraMongooseError(`Field '${field}' in type '${type.name}' exists with different type. (current: ${existingFieldType.type}, new: ${newFieldType})`);
}
}
else {
fieldsToAdd.fields[field] = newField;
}
}
if (Object.keys(fieldsToAdd.fields).length > 0) {
await this.alterType(type.name, { operation: { add: fieldsToAdd } });
updated.push(type.name);
}
}
}
}
catch (err) {
throw new astraMongooseError_1.AstraMongooseError(`Error in syncTypes: ${err instanceof Error ? err.message : err}`, { created, updated, dropped });
}
return { created, updated, dropped };
}
/**
* Execute a command against the database.
* @param command The command to be executed.
*/
async command(command) {
return await this.astraDb.command(command);
}
}
exports.BaseDb = BaseDb;
/**
* Db instance that creates and manages collections.
* @extends BaseDb
*/
class CollectionsDb extends BaseDb {
/**
* Creates an instance of CollectionsDb. Do not instantiate this class directly.
* @param astraDb The AstraDb instance to interact with the database.
* @param keyspaceName The name of the keyspace to use.
*/
constructor(astraDb, keyspaceName) {
super(astraDb, keyspaceName, false);
}
/**
* Get a collection by name.
* @param name The name of the collection.
*/
collection(name, options) {
return this.astraDb.collection(name, options);
}
/**
* Send a CreateCollection command to Data API.
*/
async createCollection(name, options) {
return await this.astraDb.createCollection(name, options);
}
}
exports.CollectionsDb = CollectionsDb;
/**
* Db instance that creates and manages tables.
* @extends BaseDb
*/
class TablesDb extends BaseDb {
/**
* Creates an instance of TablesDb. Do not instantiate this class directly.
* @param astraDb The AstraDb instance to interact with the database.
* @param keyspaceName The name of the keyspace to use.
*/
constructor(astraDb, keyspaceName) {
super(astraDb, keyspaceName, true);
}
/**
* Get a table by name. This method is called `collection()` for compatibility with Mongoose, which calls
* this method for getting a Mongoose Collection instance, which may map to a table in Astra DB when using tables mode.
* @param name The name of the table.
*/
collection(name, options) {
return this.astraDb.table(name, options);
}
/**
* Throws an error, astra-mongoose does not support creating collections in tables mode.
*/
async createCollection(name, options) {
throw new astraMongooseError_1.AstraMongooseError('Cannot createCollection in tables mode; use createTable instead', { name, options });
}
}
exports.TablesDb = TablesDb;
//# sourceMappingURL=db.js.map