dynogels
Version:
DynamoDB data mapper
425 lines (348 loc) • 13.8 kB
JavaScript
'use strict';
const dynogels = require('../../index');
const chai = require('chai');
const expect = chai.expect;
const _ = require('lodash');
const helper = require('../test-helper');
const Joi = require('joi');
chai.should();
describe('Create Tables Integration Tests', function () {
this.timeout(0);
before(() => {
dynogels.dynamoDriver(helper.realDynamoDB());
});
afterEach(() => {
dynogels.reset();
});
it('should create table with hash key', done => {
const Model = dynogels.define('dynogels-create-table-test', {
hashKey: 'id',
tableName: helper.randomName('dynogels-createtable-Accounts'),
schema: {
id: Joi.string(),
}
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.KeySchema).to.eql([{ AttributeName: 'id', KeyType: 'HASH' }]);
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'id', AttributeType: 'S' },
]);
return Model.deleteTable(done);
});
});
it('should create table with hash and range key', done => {
const Model = dynogels.define('dynogels-createtable-rangekey', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-rangekey'),
schema: {
name: Joi.string(),
age: Joi.number(),
}
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
return Model.deleteTable(done);
});
});
it('should create table with local secondary index', done => {
const Model = dynogels.define('dynogels-createtable-rangekey', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-local-idx'),
schema: {
name: Joi.string(),
age: Joi.number(),
nick: Joi.string(),
time: Joi.date()
},
indexes: [
{ hashKey: 'name', rangeKey: 'nick', type: 'local', name: 'NickIndex' },
{ hashKey: 'name', rangeKey: 'time', type: 'local', name: 'TimeIndex' },
]
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' },
{ AttributeName: 'nick', AttributeType: 'S' },
{ AttributeName: 'time', AttributeType: 'S' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
expect(desc.LocalSecondaryIndexes).to.have.length(2);
const nickIndex = _.find(desc.LocalSecondaryIndexes, { IndexName: 'NickIndex' });
expect(nickIndex.IndexName).to.eql('NickIndex');
expect(nickIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(nickIndex.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'nick', KeyType: 'RANGE' },
]);
const timeIndex = _.find(desc.LocalSecondaryIndexes, { IndexName: 'TimeIndex' });
expect(timeIndex.IndexName).to.eql('TimeIndex');
expect(timeIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(timeIndex.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'time', KeyType: 'RANGE' },
]);
return Model.deleteTable(done);
});
});
it('should create table with local secondary index with custom projection', done => {
const Model = dynogels.define('dynogels-createtable-local-proj', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-local-proj'),
schema: {
name: Joi.string(),
age: Joi.number(),
nick: Joi.string()
},
indexes: [{
hashKey: 'name',
rangeKey: 'nick',
type: 'local',
name: 'KeysOnlyNickIndex',
projection: { ProjectionType: 'KEYS_ONLY' }
}]
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' },
{ AttributeName: 'nick', AttributeType: 'S' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
const nickIndex = _.find(desc.LocalSecondaryIndexes, { IndexName: 'KeysOnlyNickIndex' });
expect(nickIndex.IndexName).to.eql('KeysOnlyNickIndex');
expect(nickIndex.Projection).to.eql({ ProjectionType: 'KEYS_ONLY' });
expect(nickIndex.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'nick', KeyType: 'RANGE' },
]);
return Model.deleteTable(done);
});
});
it('should create table with global index', done => {
const Model = dynogels.define('dynogels-createtable-global', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-global'),
schema: {
name: Joi.string(),
age: Joi.number(),
nick: Joi.string()
},
indexes: [{ hashKey: 'nick', type: 'global', name: 'GlobalNickIndex' }]
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' },
{ AttributeName: 'nick', AttributeType: 'S' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
const nickIndex = _.find(desc.GlobalSecondaryIndexes, { IndexName: 'GlobalNickIndex' });
expect(nickIndex.IndexName).to.eql('GlobalNickIndex');
expect(nickIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(nickIndex.KeySchema).to.eql([
{ AttributeName: 'nick', KeyType: 'HASH' },
]);
expect(nickIndex.ProvisionedThroughput).to.eql({ ReadCapacityUnits: 1, WriteCapacityUnits: 1 });
return Model.deleteTable(done);
});
});
it('should create table with global index with optional settings', done => {
const Model = dynogels.define('dynogels-createtable-global', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-global'),
schema: {
name: Joi.string(),
age: Joi.number(),
nick: Joi.string(),
wins: Joi.number()
},
indexes: [{
hashKey: 'nick',
type: 'global',
name: 'GlobalNickIndex',
projection: { NonKeyAttributes: ['wins'], ProjectionType: 'INCLUDE' },
readCapacity: 10,
writeCapacity: 5
}]
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' },
{ AttributeName: 'nick', AttributeType: 'S' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
const nickIndex = _.find(desc.GlobalSecondaryIndexes, { IndexName: 'GlobalNickIndex' });
expect(nickIndex.IndexName).to.eql('GlobalNickIndex');
expect(nickIndex.Projection).to.eql({ ProjectionType: 'INCLUDE', NonKeyAttributes: ['wins'] });
expect(nickIndex.KeySchema).to.eql([
{ AttributeName: 'nick', KeyType: 'HASH' },
]);
expect(nickIndex.ProvisionedThroughput).to.eql({ ReadCapacityUnits: 10, WriteCapacityUnits: 5 });
return Model.deleteTable(done);
});
});
it('should create table with global and local indexes', done => {
const Model = dynogels.define('dynogels-createtable-both-indexes', {
hashKey: 'name',
rangeKey: 'age',
tableName: helper.randomName('dynogels-createtable-both-indexes'),
schema: {
name: Joi.string(),
age: Joi.number(),
nick: Joi.string(),
wins: Joi.number()
},
indexes: [
{ hashKey: 'name', rangeKey: 'nick', type: 'local', name: 'NameNickIndex' },
{ hashKey: 'name', rangeKey: 'wins', type: 'local', name: 'NameWinsIndex' },
{ hashKey: 'nick', type: 'global', name: 'GlobalNickIndex' },
{ hashKey: 'age', rangeKey: 'wins', type: 'global', name: 'GlobalAgeWinsIndex' }
]
});
Model.createTable((err, result) => {
expect(err).to.not.exist;
const desc = result.TableDescription;
expect(desc).to.exist;
expect(desc.AttributeDefinitions).to.eql([
{ AttributeName: 'name', AttributeType: 'S' },
{ AttributeName: 'age', AttributeType: 'N' },
{ AttributeName: 'nick', AttributeType: 'S' },
{ AttributeName: 'wins', AttributeType: 'N' }
]);
expect(desc.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'age', KeyType: 'RANGE' }
]);
expect(desc.GlobalSecondaryIndexes).to.have.length(2);
const nickIndex = _.find(desc.GlobalSecondaryIndexes, { IndexName: 'GlobalNickIndex' });
expect(nickIndex.IndexName).to.eql('GlobalNickIndex');
expect(nickIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(nickIndex.KeySchema).to.eql([
{ AttributeName: 'nick', KeyType: 'HASH' },
]);
expect(nickIndex.ProvisionedThroughput).to.eql({ ReadCapacityUnits: 1, WriteCapacityUnits: 1 });
const ageWinsIndex = _.find(desc.GlobalSecondaryIndexes, { IndexName: 'GlobalAgeWinsIndex' });
expect(ageWinsIndex.IndexName).to.eql('GlobalAgeWinsIndex');
expect(ageWinsIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(ageWinsIndex.KeySchema).to.eql([
{ AttributeName: 'age', KeyType: 'HASH' },
{ AttributeName: 'wins', KeyType: 'RANGE' },
]);
expect(ageWinsIndex.ProvisionedThroughput).to.eql({ ReadCapacityUnits: 1, WriteCapacityUnits: 1 });
expect(desc.LocalSecondaryIndexes).to.have.length(2);
const nameNickIndex = _.find(desc.LocalSecondaryIndexes, { IndexName: 'NameNickIndex' });
expect(nameNickIndex.IndexName).to.eql('NameNickIndex');
expect(nameNickIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(nameNickIndex.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'nick', KeyType: 'RANGE' },
]);
const nameWinsIndex = _.find(desc.LocalSecondaryIndexes, { IndexName: 'NameWinsIndex' });
expect(nameWinsIndex.IndexName).to.eql('NameWinsIndex');
expect(nameWinsIndex.Projection).to.eql({ ProjectionType: 'ALL' });
expect(nameWinsIndex.KeySchema).to.eql([
{ AttributeName: 'name', KeyType: 'HASH' },
{ AttributeName: 'wins', KeyType: 'RANGE' },
]);
return Model.deleteTable(done);
});
});
});
describe('Update Tables Integration Tests', function () {
this.timeout(0);
let Tweet;
let tableName;
before(done => {
dynogels.dynamoDriver(helper.realDynamoDB());
tableName = helper.randomName('dynogels-updateTable-Tweets');
Tweet = dynogels.define('dynogels-update-table-test', {
hashKey: 'UserId',
rangeKey: 'TweetID',
tableName: tableName,
schema: {
UserId: Joi.string(),
TweetID: dynogels.types.uuid(),
content: Joi.string(),
PublishedDateTime: Joi.date().default(Date.now, 'now')
}
});
dynogels.createTables(done);
});
afterEach(() => {
dynogels.reset();
});
it('should add global secondary index', done => {
Tweet = dynogels.define('dynogels-update-table-test', {
hashKey: 'UserId',
rangeKey: 'TweetID',
tableName: tableName,
schema: {
UserId: Joi.string(),
TweetID: dynogels.types.uuid(),
content: Joi.string(),
PublishedDateTime: Joi.date().default(Date.now, 'now')
},
indexes: [
{ hashKey: 'UserId', rangeKey: 'PublishedDateTime', type: 'global', name: 'PublishedDateTimeIndex' }
]
});
Tweet.updateTable(err => {
expect(err).to.not.exist;
Tweet.describeTable((err, data) => {
expect(err).to.not.exist;
const globalIndexes = _.get(data, 'Table.GlobalSecondaryIndexes');
expect(globalIndexes).to.have.length(1);
const idx = _.first(globalIndexes);
expect(idx.IndexName).to.eql('PublishedDateTimeIndex');
expect(idx.KeySchema).to.eql([{ AttributeName: 'UserId', KeyType: 'HASH' },
{ AttributeName: 'PublishedDateTime', KeyType: 'RANGE' }]);
expect(idx.Projection).to.eql({ ProjectionType: 'ALL' });
return done();
});
});
});
});