Skip to content

Commit

Permalink
feat: add table.delete and dynamorm.deleteTables method
Browse files Browse the repository at this point in the history
  • Loading branch information
joshua-williams committed Mar 23, 2024
1 parent c08a6f7 commit acfe9d3
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 87 deletions.
46 changes: 46 additions & 0 deletions __tests__/create-table.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {DynamormException} from '../src/exceptions';
import {TestTable, db, client} from './fixtures/test-table';

jest.useFakeTimers()

describe('Create / Delete Table', () => {

describe('Dynamorm container instance', () => {
it('should create tables from container', async () => {
await expect(db.createTables).rejects.not.toThrow(DynamormException);
})

it('should delete tables from container', async () => {
await expect(db.deleteTables).rejects.not.toThrow(DynamormException);
})
})

describe('Table instance', () => {
let table;

beforeEach(() => {
table = new TestTable(client);
})

it('should create database table', async () => {
const createTable = async () => {
setTimeout(async () => await table.create(), 200)
}
expect(createTable).not.toThrow();
})

it('should create database table if not exists', async () => {
const createTable = async () => {
setTimeout(async () => await table.create('IF_NOT_EXISTS'), 200)
}
expect(createTable).not.toThrow(DynamormException);
})

it('should delete table', async () => {
const deleteTable = async () => {
setTimeout(async () => await table.delete(), 200)
}
expect(deleteTable).not.toThrow(DynamormException);
})
})
})
9 changes: 1 addition & 8 deletions __tests__/db.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,6 @@ describe('app', () => {

})

describe('table creation', () => {
it('should create all tables', async () => {
const result = await db.createTables();
expect(result).toBeInstanceOf(Array);
})
})

describe('save item', () => {
it('should save item', () => {
const model = db.model('AuthorEntity');
Expand All @@ -125,7 +118,7 @@ describe('app', () => {
const expectedAttributes = {
title: 'Southern Sweets',
author: '[email protected]',
image: [ 'http://images.com/logo.png' ]
image: [ 'logo.png' ]
}
expect(model).toBeInstanceOf(Model);
expect(attributes).toMatchObject(expectedAttributes)
Expand Down
2 changes: 1 addition & 1 deletion __tests__/fixtures/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ const configuration = process.env.ENVIRONMENT == 'local' ? {endpoint: "http://lo
tables: [AuthorTable, CookbookTable, RecipeTable],
models: [CookbookModel, AuthorModel]
})
class DB {}
export class DB {}

export default DynamormFactory.create(DB)
26 changes: 26 additions & 0 deletions __tests__/fixtures/test-table.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {DynamoDBClient} from '@aws-sdk/client-dynamodb';
import {attribute, dynamorm, DynamormFactory, Entity, table as TableDecorator, Table} from '../../index';

export const client = new DynamoDBClient({endpoint: 'http://localhost:8000'});

export class TestEntity extends Entity {
@attribute()
pk: string;
@attribute()
sk: string;
}

@TableDecorator({
name: 'TestTable',
primaryKey: {pk: 'pk', sk: 'sk'},
entity: TestEntity
})
export class TestTable extends Table {}

@dynamorm({
tables: [TestTable],
client
})
class DB {}

export const db = DynamormFactory.create(DB);
17 changes: 17 additions & 0 deletions __tests__/jestGlobalSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import db from './fixtures/db'

export default async function() {
await db.createTables('DROP_IF_EXISTS');
const model = db.model('Cookbooks')

await model.fill({
title: "Southern Savories",
description: 'Southern Cookbook',
author: '[email protected]',
image: ['logo.png']
}).save();
await model.set('title', 'Southern Smothered').save();
await model.set('title', 'Southern Fried').save();
await model.set('title', 'Southern Sweets').save();

}
15 changes: 8 additions & 7 deletions __tests__/model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Model from "../src/model";

const config = {endpoint: 'http://localhost:8000'};
const client = new DynamoDBClient(config);

describe('model', () => {
let model: any;

Expand Down Expand Up @@ -140,7 +141,7 @@ describe('model', () => {
it('should save', async () => {
model.fill({
title: "Southern Savories",
author: 'com.joshua360@gmail.com',
author: 'dev@studiowebfx.com',
image: ['logo.png']
});
const result = await model.save();
Expand All @@ -150,32 +151,32 @@ describe('model', () => {

describe('find', () => {
it('should get item by primary key', async () => {
const result = await model.find('Southern Savories','com.joshua360@gmail.com');
const result = await model.find('Southern Savories','dev@studiowebfx.com');
expect(result).toBeInstanceOf(Model)
expect(result.title).toEqual('Southern Savories')
expect(result.author).toEqual('com.joshua360@gmail.com')
expect(result.author).toEqual('dev@studiowebfx.com')
})
})

describe('delete', () => {
it('should delete item by primary key', async () => {
await model.fill({
title: 'Southern Savories',
author: 'com.joshua360@gmail.com',
author: 'dev@studiowebfx.com',
image: ['image.png']
}).save();
const result = await model.delete('Southern Savories','com.joshua360@gmail.com');
const result = await model.delete('Southern Savories','dev@studiowebfx.com');
expect(result).toBe(true);
})
})

describe('update', () => {
it('should update item', async () => {
model.fill({
title: 'Southern Smothered',
title: 'Southern Crunch',
author: '[email protected]',
description: 'Another Cookbook',
image: ["http://images.com/logo.png", "http://images.com/logo2.png"]
image: ["logo.png", "logo2.png"]
})
const updateModel = async () => await model.update();
expect(updateModel).not.toThrow()
Expand Down
76 changes: 41 additions & 35 deletions __tests__/query.spec.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,18 @@
import QueryBuilder from '../src/query';
import db from './fixtures/db';
import {Model} from '../index';
import {QueryException} from '../src/exceptions';
import { DB } from './fixtures/db';
import {Model, DynamormFactory} from '../index';
import {DynamormException, QueryException} from '../src/exceptions';
import {DynamormIoC} from '../src/types';

describe('Query', () => {
let query: QueryBuilder;
let db: DynamormIoC;

beforeEach(() => {
db = DynamormFactory.create(DB);
query = new QueryBuilder(db);
})

describe('Delete', () => {

beforeEach( async () => {
const cookbook = db.model('Cookbooks');
await cookbook.fill({
title: 'Haggis Cookbook',
author: 'no author',
image: ['cover.png']
}).save();
});

it('should fail to delete if sort key is not set', async () => {
const deleteCookbook = async () => {
await query
.table('Cookbooks')
.where('title', '=', 'Haggis Cookbook')
.delete()
}

await expect(deleteCookbook).rejects.toThrowError(QueryException)
});

it('should delete item from table', async () => {
await query
.table('Cookbooks')
.where('title', '=', 'Haggis Cookbook')
.and('author', '=', 'no author')
.delete()
});

})

describe('Select', () => {
it('should select specified attributes', async () => {
const model = await query
Expand Down Expand Up @@ -80,6 +51,41 @@ describe('Query', () => {
})
})

describe('Delete', () => {

beforeEach( async () => {
const cookbook = db.model('Cookbooks');
await cookbook.fill({
title: 'Haggis Cookbook',
author: 'no author',
image: ['cover.png']
}).save();
});

it('should fail to delete if sort key is not set', async () => {
const deleteCookbook = async () => {
await query
.table('Cookbooks')
.where('title', '=', 'Haggis Cookbook')
.delete()
}

await expect(deleteCookbook).rejects.toThrowError(QueryException)
});

it('should delete item from table', async () => {
const deleteItem = async () => {
await query
.table('Cookbooks')
.where('title', '=', 'Haggis Cookbook')
.and('author', '=', 'no author')
.delete()
}
expect(deleteItem).not.toThrow(DynamormException)
});

})

describe('Operators', () => {
it('AND Logical Operator', async () => {
const collection = await query
Expand Down
29 changes: 1 addition & 28 deletions __tests__/table.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import db from "./fixtures/db";
import {attribute, Entity, Table, table as TableDecorator} from "../index";
import { Table } from "../index";
import { CookbookTable } from "./fixtures/tables";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";

Expand Down Expand Up @@ -35,19 +35,6 @@ describe('table', () => {
})

describe('Create Table', () => {
class TestEntity extends Entity {
@attribute()
pk: string;
@attribute()
sk: string;
}

@TableDecorator({
name: 'TestTable',
primaryKey: {pk: 'pk', sk: 'sk'},
entity: TestEntity
})
class TestTable extends Table {}

it('should output CreateCommandInput', () => {
const expectedCommandInput = {
Expand All @@ -66,17 +53,7 @@ describe('table', () => {
expect(createCommandInput).toMatchObject(expectedCommandInput)
})

it('should create database table', async () => {
table = new CookbookTable(client);
const result = await table.create();
expect(result).toHaveProperty('TableDescription');
})

it('should create database table if not exists', async () => {
table = new TestTable(client);
const result = await table.create('IF_NOT_EXISTS');
expect(result).toHaveProperty('TableDescription');
})
})

it('should getPrimaryKeyDefinition', () => {
Expand All @@ -88,10 +65,6 @@ describe('table', () => {
expect(expectedDefinition).toMatchObject(primaryKeyDefinition)
})

it('should create table from table instance', async () => {
const result = await table.create();
expect(result).toHaveProperty('KeySchema');
})
it('should get information about existing table', async () => {
table = new CookbookTable(client);
const tableInfo = await table.describe();
Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: [ "**/__tests__/**/*.(spec|test).ts" ]
testMatch: [ "**/__tests__/**/*.(spec|test).ts" ],
globalSetup: './__tests__/jestGlobalSetup.ts'
};
16 changes: 14 additions & 2 deletions src/dynamorm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from "@aws-sdk/client-dynamodb";
import Model from "./model";
import {Entity} from "../index";
import {DynamormIoC, EntityConstructor, ModelConstructor, TableConstructor} from "./types";
import {CreateTableOption, DynamormIoC, EntityConstructor, ModelConstructor, TableConstructor} from "./types";
import QueryBuilder from './query';
/**
* @todo throw error if tables or client is undefined
Expand Down Expand Up @@ -50,16 +50,28 @@ export class DynamoRM implements DynamormIoC {
}
}

public async createTables(): Promise<CreateTableCommandOutput[]> {
public async createTables(option?: CreateTableOption): Promise<CreateTableCommandOutput[]> {
const results = [];
for ( let Constructor of this.tables ) {
const table = new Constructor(this.client);
if (option) {
const exists = await table.exists();
if (option == 'IF_NOT_EXISTS' && exists) continue;
if (option == 'DROP_IF_EXISTS' && exists) await table.delete();
}
const result = await table.create(Constructor)
results.push(result);
}
return results;
}

public async deleteTables() {
for (let Constructor of this.tables ) {
const table = new Constructor(this.client);
await table.delete(Constructor);
}
}

getModels(): Array<ModelConstructor> {
return this.models;
}
Expand Down
Loading

0 comments on commit acfe9d3

Please sign in to comment.