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

DeleteTable Implementation #524

Merged
merged 5 commits into from
Jul 29, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ __*
*.env
temp
**/.DS_Store.DS_Store
*.pem
11 changes: 11 additions & 0 deletions src/table/errors/StorageErrorFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,15 @@ export default class StorageErrorFactory {
context
);
}

public static getTableNotFound(context: Context): StorageError {
return new StorageError(
404,
"TableNotFound",
"The table specified does not exist.",
context.contextID || defaultID,
undefined,
context
);
}
}
39 changes: 24 additions & 15 deletions src/table/handlers/TableHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
NO_METADATA_ACCEPT,
RETURN_CONTENT,
RETURN_NO_CONTENT,
TABLE_API_VERSION,
TABLE_API_VERSION
} from "../utils/constants";
import { newEtag } from "../utils/utils";
import BaseHandler from "./BaseHandler";
Expand Down Expand Up @@ -138,23 +138,27 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
}

public async delete(
table: string,
tablename: string,
options: Models.TableDeleteMethodOptionalParams,
context: Context
): Promise<Models.TableDeleteResponse> {
// e.g
// const tableCtx = new TableStorageContext(context);
// const accountName = tableCtx.account;
// const tableName = tableCtx.tableName; // Get tableName from context
// return {
// statusCode: 204,
// clientRequestId: "clientRequestId",
// requestId: "requestId",
// version: "version"
// };
const tableCtx = new TableStorageContext(context);
const accountName = tableCtx.account;
// currently the tableName is not coming through, so we take it from the table context
await this.metadataStore.deleteTable(
context,
tableCtx.tableName!,
accountName!
);
const response: Models.TableDeleteResponse = {
clientRequestId: options.requestId,
requestId: tableCtx.contextID,
version: TABLE_API_VERSION,
date: context.startTime,
statusCode: 204
};

// TODO
throw new NotImplementedError();
return response;
}

public async queryEntities(
Expand Down Expand Up @@ -341,7 +345,12 @@ export default class TableHandler extends BaseHandler implements ITableHandler {
const id = `${protocol}://${host}/Tables(${tableName})`;
const editLink = `Tables(${tableName})`;

await this.metadataStore.insertTableEntity(context, tableName, entity);
await this.metadataStore.insertTableEntity(
context,
tableName,
accountName!,
entity
);

const response: Models.TableInsertEntityResponse = {
clientRequestId: options.requestId,
Expand Down
7 changes: 6 additions & 1 deletion src/table/persistence/ITableMetadataStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ export type TableModel = ITtableAdditionalProperties;
export default interface ITableMetadataStore {
queryTable(context: Context): Promise<Models.TableResponseProperties[]>;
createTable(context: Context, table: TableModel): Promise<void>;
deleteTable(context: Context, tableName: string): Promise<void>;
deleteTable(
context: Context,
tableName: string,
accountName: string
): Promise<void>;
queryTableEntities(
context: Context,
table: string,
Expand Down Expand Up @@ -60,6 +64,7 @@ export default interface ITableMetadataStore {
insertTableEntity(
context: Context,
tableName: string,
account: string,
entity: IEntity
): Promise<void>;
getTableAccessPolicy(
Expand Down
56 changes: 41 additions & 15 deletions src/table/persistence/LokiTableMetadataStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,29 @@ export default class LokiTableMetadataStore implements ITableMetadataStore {
return this.closed;
}

public async createTable(
context: Context,
table: TableModel
): Promise<void> {
public async createTable(context: Context, table: TableModel): Promise<void> {
const tablename = this.getTableCollectionNameString(
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
table.account,
table.tableName
);
const coll = this.db.getCollection(this.TABLE_COLLECTION);
const doc = coll.findOne({
accountName: table.account,
name: table.tableName
// ToDO REMOVE: accountName: table.account,
tableName: tablename
});
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved

// If the metadata exists, we will throw getTableAlreadyExists error
if (doc) {
throw StorageErrorFactory.getTableAlreadyExists(context);
}

table.tableName = tablename;
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
coll.insert(table);

const extentColl = this.db.getCollection(table.tableName);
const extentColl = this.db.getCollection(tablename);
if (extentColl) {
throw StorageErrorFactory.getTableAlreadyExists(context);
}

this.db.addCollection(table.tableName, {
this.db.addCollection(tablename, {
// Optimization for indexing and searching
// https://rawgit.com/techfort/LokiJS/master/jsdoc/tutorial-Indexing%20and%20Query%20performance.html
indices: ["ParititionKey", "RowKey"]
Expand All @@ -61,9 +61,12 @@ export default class LokiTableMetadataStore implements ITableMetadataStore {
public async insertTableEntity(
context: Context,
tableName: string,
account: string,
entity: IEntity
): Promise<void> {
const tableColl = this.db.getCollection(tableName);
const tableColl = this.db.getCollection(
this.getTableCollectionNameString(account, tableName)
);
if (!tableColl) {
throw StorageErrorFactory.getTableNotExist(context);
}
Expand All @@ -90,10 +93,27 @@ export default class LokiTableMetadataStore implements ITableMetadataStore {

public async deleteTable(
context: Context,
tableName: string
name: string,
account: string
): Promise<void> {
// TODO context: Context
throw new NotImplementedError();
const tablename = this.getTableCollectionNameString(account, name);
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
const tableColl = this.db.getCollection(tablename);
// delete the collection / table
if (tableColl != null) {
this.db.removeCollection(tablename);
} else {
throw StorageErrorFactory.getTableNotFound(context);
}
// remove table reference from collection registry
const coll = this.db.getCollection(this.TABLE_COLLECTION);
const doc = coll.findOne({
tableName: tablename
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
});
if (doc != null) {
coll.remove(doc);
} else {
throw StorageErrorFactory.getTableNotFound(context);
}
}

public async queryTableEntities(
Expand Down Expand Up @@ -184,7 +204,7 @@ export default class LokiTableMetadataStore implements ITableMetadataStore {
this.db.addCollection(this.TABLE_COLLECTION, {
// Optimization for indexing and searching
// https://rawgit.com/techfort/LokiJS/master/jsdoc/tutorial-Indexing%20and%20Query%20performance.html
indices: ["accountName", "name"]
indices: ["accountName", "tableName"]
}); // Optimize for find operation
}

Expand Down Expand Up @@ -215,4 +235,10 @@ export default class LokiTableMetadataStore implements ITableMetadataStore {

this.closed = true;
}
private getTableCollectionNameString(
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
accountName: string,
tableName: string
): string {
return accountName + tableName;
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
}
}
53 changes: 52 additions & 1 deletion tests/table/apis/table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { configLogger } from "../../../src/common/Logger";
import TableConfiguration from "../../../src/table/TableConfiguration";
import TableServer from "../../../src/table/TableServer";
import { TABLE_API_VERSION } from "../../../src/table/utils/constants";
import { EMULATOR_ACCOUNT_KEY, EMULATOR_ACCOUNT_NAME, getUniqueName, overrideRequest } from "../../testutils";
import {
EMULATOR_ACCOUNT_KEY,
EMULATOR_ACCOUNT_NAME,
getUniqueName,
overrideRequest
} from "../../testutils";
// import { options } from "args";
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved

// Set true to enable debug log
configLogger(false);
Expand Down Expand Up @@ -120,4 +126,49 @@ describe("table APIs test", () => {
// TODO
done();
});

it("deleteTable that exists, @loki", done => {
/*
https://docs.microsoft.com/en-us/rest/api/storageservices/delete-table
*/
requestOverride.headers = {
Prefer: "return-content",
accept: "application/json;odata=fullmetadata"
};

edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
const tableToDelete = tableName + "del";

tableService.createTable(tableToDelete, (error, result, response) => {
if (!error) {
tableService.deleteTable(tableToDelete, (deleteError, deleteResult) => {
if (!deleteError) {
// no body expected, we expect 204 no content on successful deletion
assert.equal(deleteResult.statusCode, 204);
} else {
assert.ifError(deleteError);
}
done();
});
} else {
assert.fail("Test failed to create the table");
done();
}
});
});

it("deleteTable that does not exist, @loki", done => {
/*
https://docs.microsoft.com/en-us/rest/api/storageservices/delete-table
*/
requestOverride.headers = {
accept: "application/json;"
};
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved

const tableToDelete = tableName + "causeerror";

tableService.deleteTable(tableToDelete, (error, result) => {
assert.equal(result.statusCode, 404); // no body expected, we expect 404
edwin-huber marked this conversation as resolved.
Show resolved Hide resolved
done();
});
});
});