Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for createTable(), listTables(), dropTable(), createIndex(), dropIndex() #244

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api-compatibility.versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
stargate_version=v2.1.0-BETA-14
data_api_version=v1.0.16
stargate_version=v2.1.0-BETA-18
data_api_version=v1.0.17
52 changes: 52 additions & 0 deletions src/collections/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,58 @@ export class Collection {
});
}

/**
*
* @param column
* @param indexName
* @returns Promise
*/
async createIndex(column: string, indexName: string) {
if (column == null) {
throw new TypeError(`Must specify a column when calling createIndex, got ${column}`);
}
if (indexName == null) {
throw new TypeError(`Must specify an indexName when calling createIndex, got ${indexName}`);
}
return executeOperation(async () => {
const command = {
addIndex: {
column,
indexName
}
};
return await this.httpClient.executeCommandWithUrl(
this.httpBasePath,
command,
null
);
});
}

/**
*
* @param column
* @param indexName
* @returns Promise
*/
async dropIndex(indexName: string) {
if (indexName == null) {
throw new TypeError(`Must specify an indexName when calling dropIndex, got ${indexName}`);
}
return executeOperation(async () => {
const command = {
dropIndex: {
indexName
}
};
return await this.httpClient.executeCommandWithUrl(
this.httpBasePath,
command,
null
);
});
}

async runCommand(command: Record<string, any>) {
return executeOperation(async () => {
return await this.httpClient.executeCommandWithUrl(
Expand Down
62 changes: 62 additions & 0 deletions src/collections/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { HTTPClient } from '@/src/client';
import {
CreateCollectionOptions,
createCollectionOptionsKeys,
CreateTableDefinition,
ListCollectionOptions,
listCollectionOptionsKeys
} from './options';
Expand Down Expand Up @@ -84,6 +85,67 @@ export class Db {
});
}

/**
*
* @param name
* @param options
* @returns Promise
*/
async createTable(name: string, definition: CreateTableDefinition) {
if (name == null) {
throw new TypeError(`Must specify a name when calling createTable, got ${name}`);
}
return executeOperation(async () => {
const command = {
createTable: {
name,
definition
}
};
return await this.httpClient.executeCommandWithUrl(
this.httpBasePath,
command,
null
);
});
}

async listTables() {
return executeOperation(async () => {
const command = {
listTables: {}
};
return await this.httpClient.executeCommandWithUrl(
this.httpBasePath,
command,
null
);
});
}

/**
*
* @param name
* @returns Promise
*/
async dropTable(name: string) {
if (name == null) {
throw new TypeError(`Must specify a name when calling dropTable, got ${name}`);
}
return executeOperation(async () => {
const command = {
dropTable: {
name
}
};
return await this.httpClient.executeCommandWithUrl(
this.httpBasePath,
command,
null
);
});
}

/**
*
* @param collectionName
Expand Down
7 changes: 7 additions & 0 deletions src/collections/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ export const createCollectionOptionsKeys: Set<string> = new Set(
Object.keys(new _CreateCollectionOptions)
);

type TableDataTypes = 'text' | 'int' | 'boolean' | 'bigint' | 'decimal' | 'double' | 'float' | 'smallint' | 'tinyint' | 'varint' | 'ascii';

export interface CreateTableDefinition {
columns: Record<string, { type: TableDataTypes }>,
primaryKey: string
}

class _ListCollectionOptions {
explain?: boolean = undefined;
}
Expand Down
28 changes: 19 additions & 9 deletions src/driver/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,25 @@ export class Collection extends MongooseCollection {
return this.collection.updateMany(filter, update, options);
}

/**
*
* @param fieldOrSpec
* @param options
*/
createIndex(fieldOrSpec: Record<string, any> | string, options: { name: string, [other: string]: any }) {
if (fieldOrSpec != null && typeof fieldOrSpec === 'object' && Object.keys(fieldOrSpec).length > 1) {
throw new TypeError('Can only index one key');
}
const field: string = typeof fieldOrSpec === 'string' ? fieldOrSpec : Object.keys(fieldOrSpec)[0];
if (typeof fieldOrSpec !== 'string') {
throw new TypeError('Invalid index specification');
}
if (typeof options?.name !== 'string') {
throw new TypeError('Must provide `name` option to `createIndex()`');
}
return this.collection.createIndex(field, options.name);
}

/**
* Get the estimated number of documents in a collection based on collection metadata
*/
Expand Down Expand Up @@ -331,15 +350,6 @@ export class Collection extends MongooseCollection {
throw new OperationNotSupportedError('listIndexes() Not Implemented');
}

/**
* Create index not supported.
* @param fieldOrSpec
* @param options
*/
createIndex(fieldOrSpec: any, options?: any) {
throw new OperationNotSupportedError('createIndex() Not Implemented');
}

/**
* Drop indexes not supported.
*/
Expand Down
43 changes: 42 additions & 1 deletion src/driver/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Collection } from './collection';
import { default as MongooseConnection } from 'mongoose/lib/connection';
import { STATES } from 'mongoose';
import { executeOperation } from '../collections/utils';
import { CreateCollectionOptions } from '../collections/options';
import { CreateCollectionOptions, CreateTableDefinition } from '../collections/options';

export class Connection extends MongooseConnection {
debugType = 'StargateMongooseConnection';
Expand Down Expand Up @@ -58,6 +58,31 @@ export class Connection extends MongooseConnection {
});
}

async createTable(name: string, definition: CreateTableDefinition) {
return executeOperation(async () => {
await this._waitForClient();
const db = this.client.db();
return db.createTable(name, definition);
});
}

async listTables(): Promise<string[]> {
return executeOperation(async () => {
await this._waitForClient();
const db = this.client.db();
const res: { status: { tables: string[] } } = await db.listTables();
return res.status.tables;
});
}

async createIndex(column: string, indexName: string) {
return executeOperation(async () => {
await this._waitForClient();
const db = this.client.db();
return db.createIndex(column, indexName);
});
}

async dropCollection(name: string) {
return executeOperation(async () => {
await this._waitForClient();
Expand All @@ -66,6 +91,22 @@ export class Connection extends MongooseConnection {
});
}

async dropTable(name: string) {
return executeOperation(async () => {
await this._waitForClient();
const db = this.client.db();
return db.dropTable(name);
});
}

async dropIndex(name: string) {
return executeOperation(async () => {
await this._waitForClient();
const db = this.client.db();
return db.dropTable(name);
});
}

async dropDatabase() {
return executeOperation(async () => {
await this._waitForClient();
Expand Down
45 changes: 43 additions & 2 deletions tests/collections/collection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ describe(`StargateMongoose - ${testClientName} Connection - collections.collecti
error = e;
}
assert.ok(error);
assert.strictEqual(error.errors[0].message, 'Failed to insert document with _id \'docml10\': Document already exists with the given _id');
assert.strictEqual(error.errors[0].message, 'Failed to insert document with _id docml10: Document already exists with the given _id');
assert.strictEqual(error.errors[0].errorCode, 'DOCUMENT_ALREADY_EXISTS');
assert.strictEqual(error.status.insertedIds.length, 10);
docList.slice(0, 10).forEach((doc, index) => {
Expand Down Expand Up @@ -315,7 +315,7 @@ describe(`StargateMongoose - ${testClientName} Connection - collections.collecti
error = e;
}
assert.ok(error);
assert.strictEqual(error.errors[0].message, 'Failed to insert document with _id \'docml10\': Document already exists with the given _id');
assert.strictEqual(error.errors[0].message, 'Failed to insert document with _id docml10: Document already exists with the given _id');
assert.strictEqual(error.errors[0].errorCode, 'DOCUMENT_ALREADY_EXISTS');
assert.strictEqual(error.status.insertedIds.length, 19);
//check if response insertedIds contains all the docs except the one that failed
Expand Down Expand Up @@ -2808,4 +2808,45 @@ describe(`StargateMongoose - ${testClientName} Connection - collections.collecti
assert.strictEqual(count, 0);
});
});

describe('tables and indexes', () => {
const tableName = 'test_table';

before(function () {
if (isAstra) {
return this.skip();
}
if (!process.env.TABLES_ENABLED) {
return this.skip();
}
});

before(async () => {
await db.createTable(tableName, {
primaryKey: 'id',
columns: { id: { type: 'text' }, age: { type: 'int' } }
});
});

after(async () => {
if (isAstra || !process.env.TABLES_ENABLED) {
return;
}
await db.dropTable(tableName);
});

it('can create and drop index', async function() {
await db.collection(tableName).createIndex('age', 'ageindex');

await db.collection(tableName).insertOne({ id: 'test', age: 42 });
const doc = await db.collection(tableName).findOne({ age: 42 });
assert.strictEqual(doc!.id, 'test');

await db.collection(tableName).dropIndex('ageindex');
await assert.rejects(
() => db.collection(tableName).findOne({ age: 42 }),
/NO_INDEX_ERROR/
);
});
});
});
33 changes: 33 additions & 0 deletions tests/collections/db.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,37 @@ describe('StargateMongoose - collections.Db', async () => {
}
});
});

describe('tables', function () {
before(function () {
if (isAstra) {
return this.skip();
}
if (!process.env.TABLES_ENABLED) {
return this.skip();
}
});

it('should create and drop a table', async () => {
const name = TEST_COLLECTION_NAME + '_table';
const db = new Db(httpClient, parseUri(dbUri).keyspaceName);
await db.createTable(
name,
{
primaryKey: 'id',
columns: { id: { type: 'text' }, age: { type: 'int' } }
}
);

await db.collection(name).insertOne({ id: 'test', age: 42 });
const doc = await db.collection(name).findOne({ id: 'test' });
assert.equal(doc!.age, 42);

await db.dropTable(name);
await assert.rejects(
() => db.collection(name).insertOne({ id: 'test', age: 42 }),
/COLLECTION_NOT_EXIST/
);
});
});
});
Loading
Loading