noppoMan/npdynamodb

View on GitHub
test/query_builder_read_spec.js

Summary

Maintainability
F
1 wk
Test Coverage
'use strict';

var Promise = require('bluebird')
var chai = require('chai');
var expect = chai.expect;
var _ = require('lodash');

var npdynamodb = require('../index');
var npd = npdynamodb.createClient(require('./dynamodb_2012_08_10'));

var complexTableData = require('./data/complex_table_seed');

function expectQueryResult(data, count, startIndex, done){
  expect(data.Count).to.equal(count);
  data.Items.forEach(function(item, i){
    expect(item.hash_key).to.equal('key1');
    expect(item.range_key).to.equal(startIndex+i);
  });
  done();
}

function expectQueryResultMinus(data, count, startIndex, done){
  expect(data.Count).to.equal(count);
  data.Items.forEach(function(item, i){
    expect(item.hash_key).to.equal('key1');
    expect(item.range_key).to.equal(startIndex-i);
  });
  done();
}

describe('QueryBuilder', function(){
  before(function(done){
    npd().rawClient().createTable(require('./data/test_tables').compex_table)
    .then(function(){
      return npd().table('complex_table').create(complexTableData);
    })
    .then(function(){
      done();
    })
    .catch(function(err){
      done(err);
    });
  });

  after(function(done){
    npd().rawClient().deleteTable({
      TableName: 'complex_table'
    })
    .then(function(){
      done();
    })
    .catch(function(err){
      done(err);
    });
  });

  describe('all', function(){
    it('Should get amount of rows', function(done){
      npd().table('complex_table').all()
      .then(function(data){
        expectQueryResult(data, 10, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('select', function(){
    it('Should get row with specified attributes', function(done){
      npd().table('complex_table')
      .select('document', 'numberSet')
      .where('hash_key', 'key1')
      .where('range_key', 1)
      .then(function(data){
        var item = data.Items[0];
        expect(item.hash_key).to.equal(undefined);
        expect(item).to.have.property("document");
        expect(item).to.have.property("numberSet");
        done();
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('where*', function(){
    it('Should find row with where(hash_key=key1 and range_key=1)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', 1)
      .then(function(data){
        expectQueryResult(data, 1, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with where(hash_key=key1 and range_key > 8)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', '>', 8)
      .then(function(data){
        expectQueryResult(data, 2, 9, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with where(hash_key=key1 and range_key >= 8)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', '>=', 8)
      .then(function(data){
        expectQueryResult(data, 3, 8, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with where(hash_key=key1 and range_key <= 3)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', '<=', 3)
      .then(function(data){
        expectQueryResult(data, 3, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with where(hash_key=key1 and range_key < 3)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', '<', 3)
      .then(function(data){
        expectQueryResult(data, 2, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with whereBetween', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .whereBetween('range_key', 1, 3)
      .then(function(data){
        expectQueryResult(data, 3, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should take multiple items with whereIn and single key', function(done){
      var tableName = 'where_in_test';
      npd().rawClient().createTable({
        AttributeDefinitions: [
          { AttributeName: 'hk', AttributeType: 'S' },
        ],
        KeySchema: [
          { AttributeName: 'hk', KeyType: 'HASH' },
        ],
        TableName: tableName,
        ProvisionedThroughput: {
          ReadCapacityUnits: 100, WriteCapacityUnits: 100
        },
      })
      .then(function(data){
        return npd().table(tableName).create([
          {
            hk: 'key1',
            foo: 'bar'
          },
          {
            hk: 'key2',
            foo: 'bar'
          }
        ]);
      })
      .then(function(){
        return npd().table(tableName)
        .whereIn('hk', ['key1', 'key2'])
        .then(function(data){
          expect(data.Responses[tableName][0].hk).to.eq('key1');
          expect(data.Responses[tableName][1].hk).to.eq('key2');
          done();
        });
      })
      .catch(done)
      .finally(function(){
        return npd().rawClient().deleteTable({TableName: tableName});
        done();
      });
    });

    it('Should take multiple items with whereIn and multiple keys', function(done){
      npd().table('complex_table')
      .whereIn(['hash_key', 'range_key'], [['key1', 1], ['key1', 2]])
      .then(function(data){
        expect(data.Responses.complex_table.length).to.eq(2);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should be raised error with using where and whereIn at the same time', function(done){
      npd().table('complex_table')
      .whereIn(['hash_key', 'range_key'], [['key1', 1], ['key1', 2]])
      .where('hash_key', 'key1')
      .then(function(data){
        throw new Error('Here is never called.');
      })
      .catch(function(err){
        expect(err).to.be.an.instanceof(Error);
        done();
      });
    });
  });

  describe('filter*', function(){

    it('Should find rows with filter(range_key = 1)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '=', 1)
      .then(function(data){
        expectQueryResult(data, 1, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filter(range_key != 1)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '!=', 1)
      .then(function(data){
        expectQueryResult(data, 9, 2, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filter(range_key > 8)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '>', 8)
      .then(function(data){
        expectQueryResult(data, 2, 9, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filter(range_key >= 8)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '>=', 8)
      .then(function(data){
        expectQueryResult(data, 3, 8, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filter(range_key <= 3)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '<=', 3)
      .then(function(data){
        expectQueryResult(data, 3, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filter(range_key < 3)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filter('range_key', '<', 3)
      .then(function(data){
        expectQueryResult(data, 2, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });


    it('Should find rows with filterIn(range_key (1,2))', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterIn('range_key', 1, 2)
      .then(function(data){
        expectQueryResult(data, 2, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterBeginsWith(gsi_hash_key "g")', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterBeginsWith('gsi_hash_key', 'g')
      .then(function(data){
        expectQueryResult(data, 10, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterBeginsWith(gsi_hash_key "hoge")', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterBeginsWith('gsi_hash_key', 'hoge')
      .then(function(data){
        expect(data.Count).to.equal(0);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterBetween(range_key 1..5 )', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterBetween('range_key', 1, 5)
      .then(function(data){
        expectQueryResult(data, 5, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterContains(stringSet "foo")', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterContains('stringSet', "foo")
      .then(function(data){
        expectQueryResult(data, 10, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterContains(numberSet 2)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterContains('numberSet', 2)
      .then(function(data){
        expectQueryResult(data, 10, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterNotContains(stringSet "foo")', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterNotContains('stringSet', "foo")
      .then(function(data){
        expect(data.Count).to.equal(0);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterNotContains(numberSet 2)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterNotContains('numberSet', 2)
      .then(function(data){
        expect(data.Count).to.equal(0);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterNull(document)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterNull('document')
      .then(function(data){
        expect(data.Count).to.equal(0);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows with filterNotNull(document)', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .filterNotNull('document')
      .then(function(data){
        expectQueryResult(data, 10, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('count', function(){
    it('Num of rows Should be same as specified limit', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .count()
      .then(function(data){
        expect(data.Count).to.equal(10);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Num of rows Should be same as specified limit', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .count()
      .limit(5)
      .then(function(data){
        expect(data.Count).to.equal(5);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('limit, offset', function(){
    it('Num of rows should be same as specified limit', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .limit(4)
      .then(function(data){
        expect(data.Count).to.equal(4);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });


    it('Should get rows that are greater than LastEvaluatedKey', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .limit(5)
      .then(function(data){
        expect(data.LastEvaluatedKey).to.deep.equal({ range_key: 5, hash_key: 'key1' });
        return npd().table('complex_table')
        .where('hash_key', 'key1')
        .limit(5)
        .offset(data.LastEvaluatedKey)
        .then(function(data){
          expect(data.LastEvaluatedKey).to.deep.equal({ range_key: 10, hash_key: 'key1' });
          done();
        });
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('order', function(){

    it('Order Should be ascending', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .limit(4)
      .asc()
      .then(function(data){
        expectQueryResult(data, 4, 1, done);
      })
      .catch(function(err){
        done(err);
      });
    });


    it('Order Should be descending', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .limit(4)
      .desc()
      .then(function(data){
        expectQueryResultMinus(data, 4, 10, done);
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('indexName', function(){
    it('Should find rows by GlobalSecondaryIndex', function(done){
      npd().table('complex_table')
      .where('gsi_hash_key', 'gkey1')
      .indexName('indexName1')
      .then(function(data){
        var item = data.Items[0];
        expect(item.gsi_hash_key).to.equal('gkey1');
        done();
      })
      .catch(function(err){
        done(err);
      });
    });

    it('Should find rows by LocalSecondaryIndex', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('lsi_range_key', 1)
      .indexName('indexName2')
      .then(function(data){
        var item = data.Items[0];
        expect(item.hash_key).to.equal("key1");
        expect(item.lsi_range_key).to.equal(1);
        done();
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('events', function(){
    it('Should detect beforeQuery and afterQuery events', function(done){
      npd().table('complex_table')
      .where('hash_key', 'key1')
      .where('range_key', 1)
      .on('beforeQuery', function(params){
        expect(params).to.have.property("TableName");
        expect(params).to.have.property("KeyConditions");
      })
      .on('afterQuery', function(result){
        expect(result.Items[0].hash_key).to.equal("key1");
        expect(result.Items[0].range_key).to.equal(1);
      })
      .then(function(data){
        done();
      })
      .catch(function(err){
        done(err);
      });
    });
  });

  describe('options.timeout', function(){
    var AWS = require('aws-sdk');

    it('Should handle timeout', function(done){
      var config = {
        apiVersion: '2012-08-10',
        accessKeyId: "AWS_KEY",
        secretAccessKey: "AWS_SECRET",
        sslEnabled: false,
        region: "ap-northeast-1",
        endpoint: 'invalid.host'
      };

      var npd = npdynamodb.createClient(new AWS.DynamoDB(config), {
        timeout: 1000
      });

      npd().table('complex_table').all().then(function(data){
        throw new Error('Here is never called.');
      })
      .catch(function(err){
        expect(err.toString()).to.eq('Error: The connection has timed out.');
        done();
      });
    });
  });

  describe('options.callbacks', function(){
    it('Callbacks of beforeQuery and afterQuery should be triggered', function(done){
      var npd = npdynamodb.createClient(require('./dynamodb_2012_08_10'), {
        initialize: function(){
          this.callbacks('beforeQuery', function(){
            if(this._feature.whereConditions[1]) {
              this._feature.whereConditions[1].values = [parseInt(this._feature.whereConditions[1].values[0]())];
            }
          });

          this.callbacks('afterQuery', function(result){
            if(result.Items) {
              result.Items[0].hex = result.Items[0].binary.toString('hex');
              result.Items[0].str = result.Items[0].binary.toString('utf8');
              return npd().table('complex_table')
              .on('afterQuery', function(){
                expect(this._feature.params.hash_key).to.eq('key10');
              })
              .create({
                hash_key: "key10",
                range_key: 5,
              });
            }
          });
        }
      });

      npd().table('complex_table').where('hash_key', 'key1').where('range_key', function(){
        return '1';
      })
      .on('beforeQuery', function(params){
        expect(params.KeyConditions[1].val1).to.eq(1);
      })
      .on('afterQuery', function(result){
        expect(result.Items[0].hex).to.eq('01020304');
        expect(result.Items[0].str).to.eq('\u0001\u0002\u0003\u0004');
      })
      .then(function(result){
        done();
      })
      .catch(done);
    });
  });
});