<commit_before>'use strict';

var chai = require('chai'),
    chaiAsPromised = require('chai-as-promised'),
    sinon = require('sinon');

if (!global.Promise) {
    global.Promise = require('promise-polyfill');
}
chai.use(chaiAsPromised);
chai.should();

var aplus = require('../../lib/aplus');
describe('aplus.sort()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'each');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortBy to aplus.sort', function () {
        aplus.sortBy.should.equal(aplus.sort);
    });
    it('should spawn Promises via aplus.each', function () {
        return aplus.sort([1], function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.each.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sort([], function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sort(null, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sort(input, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort();
        return aplus.sort(input, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
});
describe('aplus.sortSeries()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'eachSeries');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortBySeries to aplus.sortSeries', function () {
        aplus.sortBySeries.should.equal(aplus.sortSeries);
    });
    it('should spawn Promises via aplus.eachSeries', function () {
        return aplus.sortSeries([1], function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.eachSeries.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sortSeries([], function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sortSeries(null, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sortSeries(input, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort();
        return aplus.sortSeries(input, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should not spawn additional promises once a promise rejects', function () {
        var promises = 0,
            error = new Error('early break');
        return aplus.sortSeries([8, 2, 5, 1, 0, 4, 3, 9, 7, 6], function (i) {
            promises += 1;
            if (i === 5) {
                throw error;
            }
            return Promise.resolve(false);
        }).then(function () {
            chai.assert.fail('Should Not Accept Promise');
        }).catch(function () {
            promises.should.equal(3);
        });
    });
});
describe('aplus.sortLimit()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'eachLimit');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortByLimit to aplus.sortLimit', function () {
        aplus.sortByLimit.should.equal(aplus.sortLimit);
    });
    it('should spawn Promises via aplus.eachLimit', function () {
        return aplus.sortLimit([1], 3, function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.eachLimit.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sortLimit([], 3, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sortLimit(null, 3, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sortLimit(input, 3, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort();
        return aplus.sortLimit(input, 3, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should not spawn additional promises once a promise rejects', function () {
        var promises = 0,
            error = new Error('early break');
        return aplus.sortLimit([8, 2, 5, 1, 0, 4, 3, 9, 7, 6], function (i) {
            promises += 1;
            if (i === 5) {
                throw error;
            }
            return Promise.resolve(false);
        }).then(function () {
            chai.assert.fail('Should Not Accept Promise');
        }).catch(function () {
            promises.should.be.lessThan(10);
        });
    });
});
<commit_msg>fix sort tests that incorrectly sorted expected results by string value instead of numerical value<commit_after>'use strict';

var chai = require('chai'),
    chaiAsPromised = require('chai-as-promised'),
    sinon = require('sinon');

if (!global.Promise) {
    global.Promise = require('promise-polyfill');
}
chai.use(chaiAsPromised);
chai.should();

var aplus = require('../../lib/aplus');
describe('aplus.sort()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'each');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortBy to aplus.sort', function () {
        aplus.sortBy.should.equal(aplus.sort);
    });
    it('should spawn Promises via aplus.each', function () {
        return aplus.sort([1], function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.each.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sort([], function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sort(null, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sort(input, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort(function (a, b) {
            return a - b;
        });
        return aplus.sort(input, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
});
describe('aplus.sortSeries()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'eachSeries');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortBySeries to aplus.sortSeries', function () {
        aplus.sortBySeries.should.equal(aplus.sortSeries);
    });
    it('should spawn Promises via aplus.eachSeries', function () {
        return aplus.sortSeries([1], function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.eachSeries.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sortSeries([], function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sortSeries(null, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sortSeries(input, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort(function (a, b) {
            return a - b;
        });
        return aplus.sortSeries(input, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should not spawn additional promises once a promise rejects', function () {
        var promises = 0,
            error = new Error('early break');
        return aplus.sortSeries([8, 2, 5, 1, 0, 4, 3, 9, 7, 6], function (i) {
            promises += 1;
            if (i === 5) {
                throw error;
            }
            return Promise.resolve(false);
        }).then(function () {
            chai.assert.fail('Should Not Accept Promise');
        }).catch(function () {
            promises.should.equal(3);
        });
    });
});
describe('aplus.sortLimit()', function () {
    var sandbox;
    beforeEach(function () {
        sandbox = sinon.sandbox.create();
        sandbox.spy(aplus, 'eachLimit');
    });
    afterEach(function () {
        sandbox.restore();
    });
    it('should alias aplus.sortByLimit to aplus.sortLimit', function () {
        aplus.sortByLimit.should.equal(aplus.sortLimit);
    });
    it('should spawn Promises via aplus.eachLimit', function () {
        return aplus.sortLimit([1], 3, function (i) {
            return Promise.resolve(i);
        }).then(function () {
            aplus.eachLimit.called.should.equal(true);
        });
    });
    it('should accept empty input', function () {
        return aplus.sortLimit([], 3, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should accept null input', function () {
        return aplus.sortLimit(null, 3, function (i) {
            return Promise.resolve(i);
        }).then(function (value) {
            value.should.eql([]);
        });
    });
    it('should sort input', function () {
        var input = [8, 2, 5, 1, 0, 4, 3, 9, 7, 6, 5],
            expected = [0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9];
        return aplus.sortLimit(input, 3, function (i) {
            return Promise.resolve(i);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should sort large input', function () {
        var input = [],
            expected;
        for (var i = 0; i < 100; i += 1) {
            input.push(Math.random());
        }
        expected = input.slice();
        expected.sort(function (a, b) {
            return a - b;
        });
        return aplus.sortLimit(input, 3, function (j) {
            return Promise.resolve(j);
        }).then(function (output) {
            output.should.eql(expected);
        });
    });
    it('should not spawn additional promises once a promise rejects', function () {
        var promises = 0,
            error = new Error('early break');
        return aplus.sortLimit([8, 2, 5, 1, 0, 4, 3, 9, 7, 6], function (i) {
            promises += 1;
            if (i === 5) {
                throw error;
            }
            return Promise.resolve(false);
        }).then(function () {
            chai.assert.fail('Should Not Accept Promise');
        }).catch(function () {
            promises.should.be.lessThan(10);
        });
    });
});
<|endoftext|>


<commit_before>var Async = require('async');
var Joi = require('joi');
var Lab = require('lab');
var Code = require('code');
var ObjectAssign = require('object-assign');
var Proxyquire = require('proxyquire');
var Config = require('../config');

var lab = exports.lab = Lab.script();
var stub = {
    salesforce: {}
};
var BaseModel = Proxyquire('../../lib/base-model', {
    salesforce: stub.salesforce
});

lab.experiment('BaseModel Validation', function () {

    lab.test('should return the Joi validation results of a SubClass', function (done) {

        var SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel.schema = Joi.object().keys({
            name: Joi.string().required()
        });

        Code.expect(SubModel.validate()).to.be.an.object();

        done();
    });

    lab.test('should return the Joi validation results of a SubClass instance', function (done) {

        var SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel.schema = Joi.object().keys({
            name: Joi.string().required()
        });

        var myModel = new SubModel({name: 'Stimpy'});

        Code.expect(myModel.validate()).to.be.an.object();

        done();
    });
});

lab.experiment('BaseModel Helpers', function () {

    lab.test('it returns expected results for the fields adapter', function (done) {

        var fieldsDoc = BaseModel.fieldsAdapter('one two three');
        Code.expect(fieldsDoc).to.be.an.object();
        Code.expect(fieldsDoc.one).to.equal(true);
        Code.expect(fieldsDoc.two).to.equal(true);
        Code.expect(fieldsDoc.three).to.equal(true);

        var fieldsDoc2 = BaseModel.fieldsAdapter('');
        Code.expect(Object.keys(fieldsDoc2)).to.have.length(0);

        done();
    });

    lab.test('it returns expected results for the sort adapter', function (done) {

        var sortDoc = BaseModel.sortAdapter('one -two three');
        Code.expect(sortDoc).to.be.an.object();
        Code.expect(sortDoc.one).to.equal(1);
        Code.expect(sortDoc.two).to.equal(-1);
        Code.expect(sortDoc.three).to.equal(1);

        var sortDoc2 = BaseModel.sortAdapter('');
        Code.expect(Object.keys(sortDoc2)).to.have.length(0);

        done();
    });
});

lab.experiment('BaseModel Paged Find', function () {

    var SubModel;

    lab.beforeEach(function (done) {

        SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel._sobject = 'Contact';

        BaseModel.connect(Config.salesforce, function (err, db) {

            done(err);
        });
    });

    lab.afterEach(function (done) {

        SubModel.remove({}, function (err, result) {

            BaseModel.disconnect();

            done();
        });
    });

    lab.test('it returns early when an error occurs', function (done) {

        var realCount = SubModel.count;
        SubModel.count = function (query, callback) {
            callback(Error('count failed'));
        };

        var query = {};
        var fields;
        var limit = 10;
        var page = 1;
        var sort = { id: -1 };

        SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

            Code.expect(err).to.be.an.object();
            Code.expect(results).to.not.exist();

            SubModel.count = realCount;

            done();
        });
    });

    lab.test('it returns paged results', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [{name: 'Ren'}, {name: 'Stimpy'}, {name: 'Yak'}];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 10;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });

    lab.test('it returns paged results where end item is less than total', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [{name: 'Ren'}, {name: 'Stimpy'}, {name: 'Yak'}];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 2;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });

    lab.test('it returns paged results where begin item is less than total', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [
                    {name: 'Ren'},
                    {name: 'Stimpy'},
                    {name: 'Yak'}
                ];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 2;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });
});

lab.experiment('BaseModel Proxied Methods', function () {

    var SubModel, liveTestData;

    lab.before(function (done) {

        SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel._sobject = 'Contact';

        SubModel.schema = Joi.object().keys({
            Id: Joi.string().min(15).max(18).required(),
            LastName: Joi.string().required()
        });

        BaseModel.connect(Config.salesforce, function (err, api) {

            done(err);
        });
    });

    lab.after(function (done) {

        BaseModel.disconnect();

        done();
    });

    lab.test('should insert data and return the results', function (done) {

        var testData = [
            {LastName: 'Ren'},
            {LastName: 'Stimpy'},
            {LastName: 'Yak'}
        ];

        SubModel.insert(testData, function (err, results) {

            liveTestData = results;

            Code.expect(err).to.not.exist();
            Code.expect(results).to.be.an.array();

            done(err);
        });
    });

    lab.test('should return a result array', function (done) {

        SubModel.find({LastName: 'Ren'}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.array();

            done();
        });
    });

    lab.test('should return a single result', function (done) {

        SubModel.findOne({Name: 'Ren'}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();

            done();
        });
    });

    lab.test('should return a single result via id', function (done) {

        SubModel.findById(liveTestData[0].id, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();

            done();
        });
    });

    lab.test('it updates a single object via id', function (done) {

        var update = {LastName: 'New lastName'};

        SubModel.findByIdAndUpdate(liveTestData[0].id, update, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();
            Code.expect(result.success).to.equal(true);

            done();
        });
    });

    lab.test('should update a document and return the results', function (done) {

        SubModel.findOne({Id: liveTestData[0].Id}, function (err, result) {

            var res = result;
            var remove = [
                'LastModifiedDate',
                'LastCURequestDate',
                'LastCUUpdateDate',
                'MailingAddress',
                'LastViewedDate',
                'CreatedById',
                'IsDeleted',
                'OtherAddress',
                'LastActivityDate',
                'SystemModstamp',
                'PhotoUrl',
                'IsEmailBounced',
                'LastReferencedDate',
                'LastModifiedById',
                'MasterRecordId',
                'Name',
                'JigsawContactId',
                'CreatedDate'
            ];

            remove.map(function (index) {
                delete res[index];
            });

            res.LastName = 'Chan';
            SubModel.update(res, function (err, updated) {

                Code.expect(err).to.not.exist();
                Code.expect(updated).to.be.an.object();
                Code.expect(updated.success).to.equal(true);

                done(err);
            });
        });
    });

    lab.test('should return a collection count', function (done) {

        SubModel.count({}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.a.number();

            done();
        });
    });

    lab.test('should remove documents via query', function (done) {

        SubModel.remove(liveTestData[0].id, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();
            Code.expect(result.success).to.equal(true);

            done();
        });
    });
});
<commit_msg>fix schema test<commit_after>var Async = require('async');
var Joi = require('joi');
var Lab = require('lab');
var Code = require('code');
var ObjectAssign = require('object-assign');
var Proxyquire = require('proxyquire');
var Config = require('../config');

var lab = exports.lab = Lab.script();
var stub = {
    salesforce: {}
};
var BaseModel = Proxyquire('../../lib/base-model', {
    salesforce: stub.salesforce
});

lab.experiment('BaseModel Validation', function () {

    lab.test('should return the Joi validation results of a SubClass', function (done) {

        var SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel.schema = Joi.object().keys({
            name: Joi.string().required()
        });

        Code.expect(SubModel.validate()).to.be.an.object();

        done();
    });

    lab.test('should return the Joi validation results of a SubClass instance', function (done) {

        var SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel.schema = Joi.object().keys({
            name: Joi.string().required()
        });

        var myModel = new SubModel({name: 'Stimpy'});

        Code.expect(myModel.validate()).to.be.an.object();

        done();
    });
});

lab.experiment('BaseModel Helpers', function () {

    lab.test('it returns expected results for the fields adapter', function (done) {

        var fieldsDoc = BaseModel.fieldsAdapter('one two three');
        Code.expect(fieldsDoc).to.be.an.object();
        Code.expect(fieldsDoc.one).to.equal(true);
        Code.expect(fieldsDoc.two).to.equal(true);
        Code.expect(fieldsDoc.three).to.equal(true);

        var fieldsDoc2 = BaseModel.fieldsAdapter('');
        Code.expect(Object.keys(fieldsDoc2)).to.have.length(0);

        done();
    });

    lab.test('it returns expected results for the sort adapter', function (done) {

        var sortDoc = BaseModel.sortAdapter('one -two three');
        Code.expect(sortDoc).to.be.an.object();
        Code.expect(sortDoc.one).to.equal(1);
        Code.expect(sortDoc.two).to.equal(-1);
        Code.expect(sortDoc.three).to.equal(1);

        var sortDoc2 = BaseModel.sortAdapter('');
        Code.expect(Object.keys(sortDoc2)).to.have.length(0);

        done();
    });
});

lab.experiment('BaseModel Paged Find', function () {

    var SubModel;

    lab.beforeEach(function (done) {

        SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel._sobject = 'Contact';

        BaseModel.connect(Config.salesforce, function (err, db) {

            done(err);
        });
    });

    lab.afterEach(function (done) {

        SubModel.remove({}, function (err, result) {

            BaseModel.disconnect();

            done();
        });
    });

    lab.test('it returns early when an error occurs', function (done) {

        var realCount = SubModel.count;
        SubModel.count = function (query, callback) {
            callback(Error('count failed'));
        };

        var query = {};
        var fields;
        var limit = 10;
        var page = 1;
        var sort = { id: -1 };

        SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

            Code.expect(err).to.be.an.object();
            Code.expect(results).to.not.exist();

            SubModel.count = realCount;

            done();
        });
    });

    lab.test('it returns paged results', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [{name: 'Ren'}, {name: 'Stimpy'}, {name: 'Yak'}];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 10;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });

    lab.test('it returns paged results where end item is less than total', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [{name: 'Ren'}, {name: 'Stimpy'}, {name: 'Yak'}];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 2;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });

    lab.test('it returns paged results where begin item is less than total', function (done) {

        Async.auto({
            setup: function (cb) {

                var testData = [
                    {name: 'Ren'},
                    {name: 'Stimpy'},
                    {name: 'Yak'}
                ];

                SubModel.insert(testData, cb);
            }
        }, function (err, results) {

            var query = { name: { $all: [ 'Ren', 'Stimpy', 'Yak' ] } };
            var fields;
            var limit = 2;
            var page = 1;
            var sort = { id: -1 };

            SubModel.pagedFind(query, fields, sort, limit, page, function (err, results) {

                Code.expect(err).to.not.exist();
                Code.expect(results).to.be.an.object();

                done();
            });
        });
    });
});

lab.experiment('BaseModel Proxied Methods', function () {

    var SubModel, liveTestData;

    lab.before(function (done) {

        SubModel = BaseModel.extend({
            constructor: function (attrs) {

                ObjectAssign(this, attrs);
            }
        });

        SubModel._sobject = 'Contact';

        SubModel.schema = Joi.object().keys({
            Id: Joi.string().min(15).max(18).required(),
            LastName: Joi.string().required()
        });

        BaseModel.connect(Config.salesforce, function (err, api) {

            done(err);
        });
    });

    lab.after(function (done) {

        BaseModel.disconnect();

        done();
    });

    lab.test('should insert data and return the results', function (done) {

        var testData = [
            {LastName: 'Ren'},
            {LastName: 'Stimpy'},
            {LastName: 'Yak'}
        ];

        SubModel.insert(testData, function (err, results) {

            liveTestData = results;

            Code.expect(err).to.not.exist();
            Code.expect(results).to.be.an.array();

            done(err);
        });
    });

    lab.test('should return a result array', function (done) {

        SubModel.find({LastName: 'Ren'}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.array();

            done();
        });
    });

    lab.test('should return a single result', function (done) {

        SubModel.findOne({LastName: 'Ren'}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();

            done();
        });
    });

    lab.test('should return a single result via id', function (done) {

        SubModel.findById(liveTestData[0].id, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();

            done();
        });
    });

    lab.test('it updates a single object via id', function (done) {

        var update = {
            'LastName': 'New LastName'
        };

        SubModel.findByIdAndUpdate(liveTestData[0].id, update, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();
            Code.expect(result.success).to.equal(true);

            done();
        });
    });

    lab.test('should update a document and return the results', function (done) {

        SubModel.findOne({Id: liveTestData[0].Id}, function (err, result) {

            var res = result;
            var remove = [
                'LastModifiedDate',
                'LastCURequestDate',
                'LastCUUpdateDate',
                'MailingAddress',
                'LastViewedDate',
                'CreatedById',
                'IsDeleted',
                'OtherAddress',
                'LastActivityDate',
                'SystemModstamp',
                'PhotoUrl',
                'IsEmailBounced',
                'LastReferencedDate',
                'LastModifiedById',
                'MasterRecordId',
                'Name',
                'JigsawContactId',
                'CreatedDate'
            ];

            remove.map(function (index) {
                delete res[index];
            });

            res.LastName = 'Chan';
            SubModel.update(res, function (err, updated) {

                Code.expect(err).to.not.exist();
                Code.expect(updated).to.be.an.object();
                Code.expect(updated.success).to.equal(true);

                done(err);
            });
        });
    });

    lab.test('should return a collection count', function (done) {

        SubModel.count({}, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.a.number();

            done();
        });
    });

    lab.test('should remove documents via query', function (done) {

        SubModel.remove(liveTestData[0].id, function (err, result) {

            Code.expect(err).to.not.exist();
            Code.expect(result).to.be.an.object();
            Code.expect(result.success).to.equal(true);

            done();
        });
    });
});
<|endoftext|>


<commit_before>/**
 * Created by harrisonchow on 7/10/16.
 */

/* Doc Ready Functions */
$(document).ready(function () {
    $("#web-logo").change(function () {
        readURL(this);
    });

    $("#add-exec").click(function (e) {
        e.preventDefault();
        addExec();
    });

    /* Dropzone override TODO-michael: this does ignites the dropzone div */
    Dropzone.autoDiscover = false;
    $("div#galleryDrop").dropzone({url: "website.php"});
});

/* On form submit function */
function formSubmit(theForm) {
    var submitButton = document.getElementById('website-form-submit');
    submitButton.disabled = true;

    var parseUser = theForm.dataset.parseuser,
        parsePwd = theForm.dataset.parsepw;

    Parse.initialize("developers-foundation-db", "unused");
    Parse.serverURL = 'https://developers-foundation-db.herokuapp.com/parse';

    var websiteID = theForm.dataset.websiteid;
    var formWebTitle = document.getElementById('web-title').value,
        formWebNick = document.getElementById('web-nick').value,
        formWebDesc = document.getElementById('web-description').value,
        formWebUrl = document.getElementById('web-url').value,
        formWebLogo = document.getElementById('web-logo-preview').src;

    var formWebExec = [],
        execBlocks = document.getElementsByClassName('exec-group');
    for (i = 0; i < execBlocks.length; i++) {
        formWebExec[i] = {};
        formWebExec[i].pictureid = execBlocks.getElementsByClassName('input-exec-img')[0].dataset.parsedb;
        formWebExec[i].name = execBlocks[i].getElementsByClassName('exec-name')[0].value;
        formWebExec[i].position = execBlocks[i].getElementsByClassName('exec-name')[0].value;
        formWebExec[i].desc = execBlocks[i].getElementsByClassName('exec-description')[0].value;
    }

    // Save current edits first
    switchSection(document.getElementsByClassName('content-select')[0]);
    var contentFields = document.getElementsByClassName('content-field'),
        formWebContent = {"data":[]};
    for (i = 0; i < contentFields.length; i++) {
        formWebContent.data[i] = {};
        formWebContent.data[i].name = contentFields[i].dataset.namefield;
        formWebContent.data[i].content = contentFields[i].innerHTML;
    }

    Parse.User.logIn(parseUser, parsePwd).then(function () {
        var Websites = Parse.Object.extend("Website");
        var query = new Parse.Query(Websites);
        return query.get(websiteID);
    }).then(function (obj) {
        // Promise system to make async
        var promise = Parse.Promise.as();

        obj.set('name', formWebTitle);
        obj.set('nickname', formWebNick);
        obj.set('description', formWebDesc);
        obj.set('url', formWebUrl);
        obj.set('exec',formWebExec);
        obj.set('content', formWebContent);

        if (formWebLogo.indexOf('http') != -1) {
            // Logo is hosted
            obj.set('logoUrl', formWebLogo);
        } else {
            // Logo was just uploaded and is in base64
            // Removing html trash first
            //formWebLogo = formWebLogo.substr(formWebLogo.indexOf('base64,') + 7);

            var theFile = document.getElementById('web-logo').files[0];

            // First check file size (limit is 10mb)
            if (theFile.size > 10485759) {
                $(function () {
                    new PNotify({
                        title: 'Oh No!',
                        text: 'File size limit is 10mb. Sorry!',
                        type: 'error',
                        nonblock: {
                            nonblock: true
                        },
                        styling: 'bootstrap3'
                    });
                });
                return Parse.Promise.error("File size too large.");
            }

            var formWebLogoFilename = theFile.name;
            var parseFile = new Parse.File(formWebLogoFilename, theFile);
            promise = promise.then(function () {
                return parseFile.save();
            }).then(function (img) {
                var tempUrl = img.url();
                tempUrl = (tempUrl.indexOf('https') == 0) ? tempUrl : "https" + tempUrl.substr(4);
                //console.log(tempUrl);

                // Add parse file to obj
                obj.set('logo', parseFile);
                obj.set('logoUrl', tempUrl);
                return;
            }, function (err) {
                console.log(err);
            });
        }

        promise = promise.then(function () {
            return obj.save();
        });
        return promise;
    }).then(function (obj) {
        // Object saved
        $(function () {
            new PNotify({
                title: 'Success',
                text: 'That thing that you were trying to do actually worked! heheh',
                type: 'success',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    }, function (error) {
        // The object was not retrieved successfully.
        // error is a Parse.Error with an error code and message.
        console.log(error);

        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: 'Failed to submit form :( Error ' + error.code + ': ' + error.message,
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    });

    submitButton.disabled = false;
}

/* Profile Picture */
function triggerProfilePicUpload(e, self) {
    e.preventDefault();
    self.parentNode.getElementsByClassName('input-exec-img')[0].click();
    return false;
}

function fileSubmit(self) {
    var file = self.value;
    var fileName = file.split("\\");
    if (fileName == "") fileName = "Upload Picture";
    self.parentNode.getElementsByClassName('btn')[0].innerHTML = fileName[fileName.length - 1];

    readURL(self);
    uploadExecPic(self);
    return false;
}

function uploadExecPic(self) {
    var theForm = document.getElementById('website-form'),
        parseUser = theForm.dataset.parseuser,
        parsePwd = theForm.dataset.parsepw;

    var theFile = self.files[0];

    Parse.User.logIn(parseUser, parsePwd).then(function () {
        var promise = Parse.Promise.as();

        // First check file size (limit is 10mb)
        if (theFile.size > 10485759) {
            $(function () {
                new PNotify({
                    title: 'Oh No!',
                    text: 'File size limit is 10mb. Sorry!',
                    type: 'error',
                    nonblock: {
                        nonblock: true
                    },
                    styling: 'bootstrap3'
                });
            });
            return Parse.Promise.error("File size too large.");
        }

        var ExecPhoto = Parse.Object.extend("ExecPhoto");
        var execPhotoObj = new ExecPhoto();

        var parseFile = new Parse.File(theFile.name, theFile);
        promise = promise.then(function () {
            return parseFile.save();
        }).then(function (img) {
            var tempUrl = img.url();
            tempUrl = (tempUrl.indexOf('https') == 0) ? tempUrl : "https" + tempUrl.substr(4);

            // Add parse file to obj
            execPhotoObj.set('picture', parseFile);
            execPhotoObj.set('pictureUrl', tempUrl);
            return execPhotoObj.save();
        }).then(function(rtnObj) {
            console.log(rtnObj);
        }, function (err) {
            console.log(err);
        });

        return promise;
    }, function (err) {
        console.log(err);
        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: err.message,
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    });
}

// Auto preview uploads
function readURL(input) {
    if (input.files && input.files[0] && input.files[0].size > 10485759) {
        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: 'File size limit is 10mb. Sorry!',
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
        return;
    }

    if (input.files && input.files[0]) {
        // Get destination of preview
        var preview = input.dataset.preview;
        var reader = new FileReader();

        reader.onload = function (e) {
            $(preview).attr('src', e.target.result);
        }

        reader.readAsDataURL(input.files[0]);
    }
}

/* Add exec */
function addExec() {
    var currentExecCount = document.getElementById('website-step-2').dataset.execcount,
        container = document.getElementById('website-step-2'),
        addButton = document.getElementById('add-exec'),
        newDiv = document.createElement('DIV');

    currentExecCount++;

    var inner = '
\

\
        \

\

\
        <button class="btn btn-success" name="picturePlaceHolder' + currentExecCount + '" onclick="triggerProfilePicUpload(event, this);">Upload Picture</button>\
        <input type="file" name="pictureToUpload' + currentExecCount + '" class="input-exec-img" data-role="magic-overlay" data-target="#pictureBtn"\
        data-edit="insertImage" data-preview=".preview-exec-img' + currentExecCount + '" data-parsedb="-1" style="display: none;" onchange="fileSubmit(this);"/>\

\

\

\

\
        <input type="text" id="exec-name' + currentExecCount + '" required class="form-control col-md-7 col-xs-12 exec-name" placeholder="Name">\

\

\

\
        <input type="text" id="exec-position' + currentExecCount + '" required class="form-control col-md-7 col-xs-12 exec-position" placeholder="Position">\

\

\

\
        <textarea id="exec-description' + currentExecCount + '" name="exec-description" class="form-control col-md-7 col-xs-12 exec-description" rows="5" placeholder="Information goes here"></textarea>\

\

\

\

';

    newDiv.innerHTML = inner;
    newDiv.className = "form-group exec-group";
    newDiv.dataset.exec = "" + currentExecCount;

    container.insertBefore(newDiv, addButton);
    document.getElementById('website-step-2').dataset.execcount = currentExecCount;
}

/* Switch fetch sections */
function switchSection(self) {
    var editor = document.getElementById('editor'),
        oldField = editor.dataset.contentold,
        oldData = editor.innerHTML,
        newField = self.value;
    var oldFieldDiv = document.querySelectorAll('[data-namefield~="' + oldField + '"]')[0];
    oldFieldDiv.innerHTML = oldData;

    var newFieldDiv = document.querySelectorAll('[data-namefield~="' + newField + '"]')[0];
    editor.innerHTML = newFieldDiv.innerHTML;
    editor.dataset.contentold = newField;
    return;
}
<commit_msg>init exec photo<commit_after>/**
 * Created by harrisonchow on 7/10/16.
 */

/* Doc Ready Functions */
$(document).ready(function () {
    $("#web-logo").change(function () {
        readURL(this);
    });

    $("#add-exec").click(function (e) {
        e.preventDefault();
        addExec();
    });

    /* Dropzone override TODO-michael: this does ignites the dropzone div */
    Dropzone.autoDiscover = false;
    $("div#galleryDrop").dropzone({url: "website.php"});
});

/* On form submit function */
function formSubmit(theForm) {
    var submitButton = document.getElementById('website-form-submit');
    submitButton.disabled = true;

    var parseUser = theForm.dataset.parseuser,
        parsePwd = theForm.dataset.parsepw;

    Parse.initialize("developers-foundation-db", "unused");
    Parse.serverURL = 'https://developers-foundation-db.herokuapp.com/parse';

    var websiteID = theForm.dataset.websiteid;
    var formWebTitle = document.getElementById('web-title').value,
        formWebNick = document.getElementById('web-nick').value,
        formWebDesc = document.getElementById('web-description').value,
        formWebUrl = document.getElementById('web-url').value,
        formWebLogo = document.getElementById('web-logo-preview').src;

    var formWebExec = [],
        execBlocks = document.getElementsByClassName('exec-group');
    for (i = 0; i < execBlocks.length; i++) {
        formWebExec[i] = {};
        formWebExec[i].pictureid = execBlocks.getElementsByClassName('input-exec-img')[0].dataset.parsedb;
        formWebExec[i].name = execBlocks[i].getElementsByClassName('exec-name')[0].value;
        formWebExec[i].position = execBlocks[i].getElementsByClassName('exec-name')[0].value;
        formWebExec[i].desc = execBlocks[i].getElementsByClassName('exec-description')[0].value;
    }

    // Save current edits first
    switchSection(document.getElementsByClassName('content-select')[0]);
    var contentFields = document.getElementsByClassName('content-field'),
        formWebContent = {"data":[]};
    for (i = 0; i < contentFields.length; i++) {
        formWebContent.data[i] = {};
        formWebContent.data[i].name = contentFields[i].dataset.namefield;
        formWebContent.data[i].content = contentFields[i].innerHTML;
    }

    Parse.User.logIn(parseUser, parsePwd).then(function () {
        var Websites = Parse.Object.extend("Website");
        var query = new Parse.Query(Websites);
        return query.get(websiteID);
    }).then(function (obj) {
        // Promise system to make async
        var promise = Parse.Promise.as();

        obj.set('name', formWebTitle);
        obj.set('nickname', formWebNick);
        obj.set('description', formWebDesc);
        obj.set('url', formWebUrl);
        obj.set('exec',formWebExec);
        obj.set('content', formWebContent);

        if (formWebLogo.indexOf('http') != -1) {
            // Logo is hosted
            obj.set('logoUrl', formWebLogo);
        } else {
            // Logo was just uploaded and is in base64
            // Removing html trash first
            //formWebLogo = formWebLogo.substr(formWebLogo.indexOf('base64,') + 7);

            var theFile = document.getElementById('web-logo').files[0];

            // First check file size (limit is 10mb)
            if (theFile.size > 10485759) {
                $(function () {
                    new PNotify({
                        title: 'Oh No!',
                        text: 'File size limit is 10mb. Sorry!',
                        type: 'error',
                        nonblock: {
                            nonblock: true
                        },
                        styling: 'bootstrap3'
                    });
                });
                return Parse.Promise.error("File size too large.");
            }

            var formWebLogoFilename = theFile.name;
            var parseFile = new Parse.File(formWebLogoFilename, theFile);
            promise = promise.then(function () {
                return parseFile.save();
            }).then(function (img) {
                var tempUrl = img.url();
                tempUrl = (tempUrl.indexOf('https') == 0) ? tempUrl : "https" + tempUrl.substr(4);
                //console.log(tempUrl);

                // Add parse file to obj
                obj.set('logo', parseFile);
                obj.set('logoUrl', tempUrl);
                return;
            }, function (err) {
                console.log(err);
            });
        }

        promise = promise.then(function () {
            return obj.save();
        });
        return promise;
    }).then(function (obj) {
        // Object saved
        $(function () {
            new PNotify({
                title: 'Success',
                text: 'That thing that you were trying to do actually worked! heheh',
                type: 'success',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    }, function (error) {
        // The object was not retrieved successfully.
        // error is a Parse.Error with an error code and message.
        console.log(error);

        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: 'Failed to submit form :( Error ' + error.code + ': ' + error.message,
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    });

    submitButton.disabled = false;
}

/* Profile Picture */
function triggerProfilePicUpload(e, self) {
    e.preventDefault();
    self.parentNode.getElementsByClassName('input-exec-img')[0].click();
    return false;
}

function fileSubmit(self) {
    var file = self.value;
    var fileName = file.split("\\");
    if (fileName == "") fileName = "Upload Picture";
    self.parentNode.getElementsByClassName('btn')[0].innerHTML = fileName[fileName.length - 1];

    readURL(self);
    uploadExecPic(self);
    return false;
}

function uploadExecPic(self) {
    var theForm = document.getElementById('website-form'),
        parseUser = theForm.dataset.parseuser,
        parsePwd = theForm.dataset.parsepw;

    Parse.initialize("developers-foundation-db", "unused");
    Parse.serverURL = 'https://developers-foundation-db.herokuapp.com/parse';

    var theFile = self.files[0];

    Parse.User.logIn(parseUser, parsePwd).then(function () {
        var promise = Parse.Promise.as();

        // First check file size (limit is 10mb)
        if (theFile.size > 10485759) {
            $(function () {
                new PNotify({
                    title: 'Oh No!',
                    text: 'File size limit is 10mb. Sorry!',
                    type: 'error',
                    nonblock: {
                        nonblock: true
                    },
                    styling: 'bootstrap3'
                });
            });
            return Parse.Promise.error("File size too large.");
        }

        var ExecPhoto = Parse.Object.extend("ExecPhoto");
        var execPhotoObj = new ExecPhoto();

        var parseFile = new Parse.File(theFile.name, theFile);
        promise = promise.then(function () {
            return parseFile.save();
        }).then(function (img) {
            var tempUrl = img.url();
            tempUrl = (tempUrl.indexOf('https') == 0) ? tempUrl : "https" + tempUrl.substr(4);

            // Add parse file to obj
            execPhotoObj.set('picture', parseFile);
            execPhotoObj.set('pictureUrl', tempUrl);
            return execPhotoObj.save();
        }).then(function(rtnObj) {
            console.log(rtnObj);
        }, function (err) {
            console.log(err);
        });

        return promise;
    }, function (err) {
        console.log(err);
        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: err.message,
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
    });
}

// Auto preview uploads
function readURL(input) {
    if (input.files && input.files[0] && input.files[0].size > 10485759) {
        $(function () {
            new PNotify({
                title: 'Oh No!',
                text: 'File size limit is 10mb. Sorry!',
                type: 'error',
                nonblock: {
                    nonblock: true
                },
                styling: 'bootstrap3'
            });
        });
        return;
    }

    if (input.files && input.files[0]) {
        // Get destination of preview
        var preview = input.dataset.preview;
        var reader = new FileReader();

        reader.onload = function (e) {
            $(preview).attr('src', e.target.result);
        }

        reader.readAsDataURL(input.files[0]);
    }
}

/* Add exec */
function addExec() {
    var currentExecCount = document.getElementById('website-step-2').dataset.execcount,
        container = document.getElementById('website-step-2'),
        addButton = document.getElementById('add-exec'),
        newDiv = document.createElement('DIV');

    currentExecCount++;

    var inner = '
\

\
        \

\

\
        <button class="btn btn-success" name="picturePlaceHolder' + currentExecCount + '" onclick="triggerProfilePicUpload(event, this);">Upload Picture</button>\
        <input type="file" name="pictureToUpload' + currentExecCount + '" class="input-exec-img" data-role="magic-overlay" data-target="#pictureBtn"\
        data-edit="insertImage" data-preview=".preview-exec-img' + currentExecCount + '" data-parsedb="-1" style="display: none;" onchange="fileSubmit(this);"/>\

\

\

\

\
        <input type="text" id="exec-name' + currentExecCount + '" required class="form-control col-md-7 col-xs-12 exec-name" placeholder="Name">\

\

\

\
        <input type="text" id="exec-position' + currentExecCount + '" required class="form-control col-md-7 col-xs-12 exec-position" placeholder="Position">\

\

\

\
        <textarea id="exec-description' + currentExecCount + '" name="exec-description" class="form-control col-md-7 col-xs-12 exec-description" rows="5" placeholder="Information goes here"></textarea>\

\

\

\

';

    newDiv.innerHTML = inner;
    newDiv.className = "form-group exec-group";
    newDiv.dataset.exec = "" + currentExecCount;

    container.insertBefore(newDiv, addButton);
    document.getElementById('website-step-2').dataset.execcount = currentExecCount;
}

/* Switch fetch sections */
function switchSection(self) {
    var editor = document.getElementById('editor'),
        oldField = editor.dataset.contentold,
        oldData = editor.innerHTML,
        newField = self.value;
    var oldFieldDiv = document.querySelectorAll('[data-namefield~="' + oldField + '"]')[0];
    oldFieldDiv.innerHTML = oldData;

    var newFieldDiv = document.querySelectorAll('[data-namefield~="' + newField + '"]')[0];
    editor.innerHTML = newFieldDiv.innerHTML;
    editor.dataset.contentold = newField;
    return;
}
<|endoftext|>


<commit_before>import * as d3 from "d3";
var canvas = d3.select("div")
.append("svg")
.attr("width",500)
.attr("height",500)

var grayBackground = canvas
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.attr("height", 500)
.attr("fill",d3.rgb(200, 210, 220))

var jsonData = []
var id = require('./App')
var host = window.location.hostname
var frames = 0
var ws = new WebSocket('ws://' + host + ':8080'+"/?id="+id );
      ws.onmessage = function (event) {
        frames++
      // console.log( event.data)
        jsonData = JSON.parse(event.data)
      };

var w = window.innerWidth;
var h = window.innerHeight;

var mousePosition = {x:250, y:250};
document.addEventListener('mousemove', function(mouseMoveEvent){

  if (mouseMoveEvent.pageX > 500 || mouseMoveEvent.pageX<0
   || mouseMoveEvent.pageY<0 || mouseMoveEvent.pageY >500)
{
  mousePosition.x = 250
  mousePosition.y = 250
}
else
{
  mousePosition.x = mouseMoveEvent.pageX;
  mousePosition.y = mouseMoveEvent.pageY;
}

}, false);

var sendCommand = () =>
{
setTimeout(sendCommand,16.667)
//console.log(mousePosition)
var command = { "mouse" : mousePosition }
ws.send( JSON.stringify(command)  )
}
setTimeout(sendCommand,1000)

var countFPS = () =>
{
  setTimeout(countFPS,1000)
  console.log("fps : " +frames)
  frames = 0
  console.log(JSON.stringify(jsonData,1));
}
setTimeout(countFPS,1000)

var draw = () =>
{
   canvas.selectAll("circle")
        .data ([]).exit().remove()

        canvas.selectAll("circle")
        .data (jsonData)
        .enter()
        .append("circle")
        .attr("cx", (e) => e.pos[0])
        .attr("cy", (e) => e.pos[1])
        .attr("r", (e)=> e.r)
        .attr("fill", (e) => d3.rgb(e.color[0] , e.color[1],e.color[2])  )

window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);<commit_msg>Client fix to match server position description<commit_after>import * as d3 from "d3";
var canvas = d3.select("div")
.append("svg")
.attr("width",500)
.attr("height",500)

var grayBackground = canvas
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 500)
.attr("height", 500)
.attr("fill",d3.rgb(200, 210, 220))

var jsonData = []
var id = require('./App')
var host = window.location.hostname
var frames = 0
var ws = new WebSocket('ws://' + host + ':8080'+"/?id="+id );
      ws.onmessage = function (event) {
        frames++
      // console.log( event.data)
        jsonData = JSON.parse(event.data)
      };

var w = window.innerWidth;
var h = window.innerHeight;

var mousePosition = {x:250, y:250};
document.addEventListener('mousemove', function(mouseMoveEvent){

  if (mouseMoveEvent.pageX > 500 || mouseMoveEvent.pageX<0
   || mouseMoveEvent.pageY<0 || mouseMoveEvent.pageY >500)
{
  mousePosition.x = 250
  mousePosition.y = 250
}
else
{
  mousePosition.x = mouseMoveEvent.pageX;
  mousePosition.y = mouseMoveEvent.pageY;
}

}, false);

var sendCommand = () =>
{
setTimeout(sendCommand,16.667)
//console.log(mousePosition)
var command = { "mouse" : mousePosition }
ws.send( JSON.stringify(command)  )
}
setTimeout(sendCommand,1000)

var countFPS = () =>
{
  setTimeout(countFPS,1000)
  console.log("fps : " +frames)
  frames = 0
  console.log(JSON.stringify(jsonData,1));
}
setTimeout(countFPS,1000)

var draw = () =>
{
   canvas.selectAll("circle")
        .data ([]).exit().remove()

        canvas.selectAll("circle")
        .data (jsonData)
        .enter()
        .append("circle")
        .attr("cx", (e) => e.pos.x)
        .attr("cy", (e) => e.pos.y)
        .attr("r", (e)=> e.r)
        .attr("fill", (e) => d3.rgb(e.color[0] , e.color[1],e.color[2])  )

window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);<|endoftext|>


<commit_before>'use strict';

/*jshint expr: true*/

const expect = require( 'chai' ).expect;

const joi = require( 'joi' );

const index = require( '../../lib/index' );

const sinon = require( 'sinon' );

describe( 'lib/index', function() {

    describe( '.builder', function() {

        it( 'normal operation', function() {

            let builder = index.builder();

            expect( builder.constructor.name ).to.equal( 'SchemaBuilder' );
        });
    });

    describe( 'SchemaBuilder', function() {

        describe( 'build', function() {

            let builder;

            let stringSchema;

            beforeEach( function() {

                stringSchema = {};

                stringSchema.required = sinon.stub().returns( stringSchema );
                stringSchema.trim =sinon.stub().returns( stringSchema );

                builder = index.builder();

                engine.string = sinon.stub().returns( stringSchema );
            });

            it( 'single value schema', function() {

                let schema = builder.build( 'string:required' );

                expect( schema ).to.equal( stringSchema );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });

            it( '@schema property', function() {

                let schema = builder.build( {

                        '@type': 'string',
                        required: true,
                        '@schema': true
                    });

                expect( schema ).to.equal( stringSchema );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });

            it( 'schema case', function() {

                let schema = builder.build( {

                        name: 'string:required'
                    });

                expect( schema ).to.eql( { name: stringSchema } );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });
        });
    });

    describe( 'Joi schema cases', function() {

        let parser;

        beforeEach( function() {

            parser = index.parser( joi );
        });

        it( 'string', function() {

            let schema = parser.parse( 'string: min=1, max=60, required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 3 );

            expect( schema._tests[0].name ).to.equal( 'min' );
            expect( schema._tests[0].arg ).to.equal( 1 );

            expect( schema._tests[1].name ).to.equal( 'max' );
            expect( schema._tests[1].arg ).to.equal( 60 );

            expect( schema._tests[2].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'uuid', function() {

            let schema = parser.parse( 'uuid:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'guid' );
            expect( schema._tests[1].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'email', function() {

            let schema = parser.parse( 'email:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'email' );
            expect( schema._tests[1].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'number', function() {

            let schema = parser.parse( 'number:min=1,max=10,required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'number' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'min' );
            expect( schema._tests[0].arg ).to.equal( 1 );

            expect( schema._tests[1].name ).to.equal( 'max' );
            expect( schema._tests[1].arg ).to.equal( 10 );

            expect( schema._flags.presence ).to.equal( 'required' );
        });

        it( 'boolean', function() {

            let schema = parser.parse( 'boolean:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'boolean' );
            expect( schema._tests.length ).to.equal( 0 );

            expect( schema._flags.presence ).to.equal( 'required' );
        });

        it( 'object', function() {

            let schema = parser.parse( {

                name: 'string:required',
                age: 'number'
            });

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'object' );
            expect( schema._inner.children.length ).to.equal( 2 );

            expect( schema._inner.children[0].key ).to.equal( 'name' );
            expect( schema._inner.children[0].schema._type ).to.equal( 'string' );
            expect( schema._inner.children[0].schema._flags.presence ).to.equal( 'required' );

            expect( schema._inner.children[1].key ).to.equal( 'age' );
            expect( schema._inner.children[1].schema._type ).to.equal( 'number' );
            expect( schema._inner.children[1].schema._flags.presence ).to.not.exist;
        });

        it( 'array', function() {

            let schema = parser.parse( {

                '@items': 'string:required'
            });

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'array' );

            expect( schema._inner.items.length ).to.equal( 1 );

            expect( schema._inner.items[0]._type ).to.equal( 'string' );
            expect( schema._inner.items[0]._flags.presence ).to.equal( 'required' );
        });

        it( 'alternatives []', function() {

            let schema = parser.parse( [ 'uuid:required', 'number:required' ] );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'alternatives' );

            expect( schema._inner.matches[0].schema._type ).to.equal( 'string' );
            expect( schema._inner.matches[0].schema._flags.presence ).to.equal( 'required' );

            expect( schema._inner.matches[1].schema._type ).to.equal( 'number' );
            expect( schema._inner.matches[1].schema._flags.presence ).to.equal( 'required' );

            let result1 = joi.validate( '3952469a-1b45-4d5e-825c-e25ec8b57cf6', schema );
            expect( result1.error ).to.be.null;

            let result2 = joi.validate( 42, schema );
            expect( result2.error ).to.be.null;

            let result3 = joi.validate( 'forty-two', schema );
            expect( result3.error ).to.exist;
        });
    });
});
<commit_msg>Updated tests<commit_after>'use strict';

/*jshint expr: true*/

const proxyquire = require( 'proxyquire' );

const expect = require( 'chai' ).expect;

//const index = require( '../../lib/index' );

const sinon = require( 'sinon' );

describe( 'lib/index', function() {

    let index;

    let engine;

    beforeEach( function() {

        engine = {};

        index = proxyquire( '../../lib/index', {

            'joi': engine
        });
    });

    describe( '.builder', function() {

        it( 'normal operation', function() {

            let builder = index.builder();

            expect( builder.constructor.name ).to.equal( 'SchemaBuilder' );
        });
    });

    describe( 'SchemaBuilder', function() {

        describe( 'build', function() {

            let builder;

            let stringSchema;

            beforeEach( function() {

                stringSchema = {};

                stringSchema.required = sinon.stub().returns( stringSchema );
                stringSchema.trim =sinon.stub().returns( stringSchema );

                builder = index.builder();

                engine.string = sinon.stub().returns( stringSchema );
            });

            it( 'single value schema', function() {

                let schema = builder.build( 'string:required' );

                expect( schema ).to.equal( stringSchema );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });

            it( '@schema property', function() {

                let schema = builder.build( {

                        '@type': 'string',
                        required: true,
                        '@schema': true
                    });

                expect( schema ).to.equal( stringSchema );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });

            it( 'schema case', function() {

                let schema = builder.build( {

                        name: 'string:required'
                    });

                expect( schema ).to.eql( { name: stringSchema } );

                expect( stringSchema.required.calledOnce ).to.be.true;
            });
        });
    });

    describe( 'Joi schema cases', function() {

        const joi = require( 'joi' );

        let parser;

        beforeEach( function() {

            parser = index.parser( joi );
        });

        it( 'string', function() {

            let schema = parser.parse( 'string: min=1, max=60, required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 3 );

            expect( schema._tests[0].name ).to.equal( 'min' );
            expect( schema._tests[0].arg ).to.equal( 1 );

            expect( schema._tests[1].name ).to.equal( 'max' );
            expect( schema._tests[1].arg ).to.equal( 60 );

            expect( schema._tests[2].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'uuid', function() {

            let schema = parser.parse( 'uuid:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'guid' );
            expect( schema._tests[1].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'email', function() {

            let schema = parser.parse( 'email:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'string' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'email' );
            expect( schema._tests[1].name ).to.equal( 'trim' );

            expect( schema._flags.presence ).to.equal( 'required' );
            expect( schema._flags.trim ).to.be.true;
        });

        it( 'number', function() {

            let schema = parser.parse( 'number:min=1,max=10,required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'number' );
            expect( schema._tests.length ).to.equal( 2 );

            expect( schema._tests[0].name ).to.equal( 'min' );
            expect( schema._tests[0].arg ).to.equal( 1 );

            expect( schema._tests[1].name ).to.equal( 'max' );
            expect( schema._tests[1].arg ).to.equal( 10 );

            expect( schema._flags.presence ).to.equal( 'required' );
        });

        it( 'boolean', function() {

            let schema = parser.parse( 'boolean:required' );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'boolean' );
            expect( schema._tests.length ).to.equal( 0 );

            expect( schema._flags.presence ).to.equal( 'required' );
        });

        it( 'object', function() {

            let schema = parser.parse( {

                name: 'string:required',
                age: 'number'
            });

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'object' );
            expect( schema._inner.children.length ).to.equal( 2 );

            expect( schema._inner.children[0].key ).to.equal( 'name' );
            expect( schema._inner.children[0].schema._type ).to.equal( 'string' );
            expect( schema._inner.children[0].schema._flags.presence ).to.equal( 'required' );

            expect( schema._inner.children[1].key ).to.equal( 'age' );
            expect( schema._inner.children[1].schema._type ).to.equal( 'number' );
            expect( schema._inner.children[1].schema._flags.presence ).to.not.exist;
        });

        it( 'array', function() {

            let schema = parser.parse( {

                '@items': 'string:required'
            });

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'array' );

            expect( schema._inner.items.length ).to.equal( 1 );

            expect( schema._inner.items[0]._type ).to.equal( 'string' );
            expect( schema._inner.items[0]._flags.presence ).to.equal( 'required' );
        });

        it( 'alternatives []', function() {

            let schema = parser.parse( [ 'uuid:required', 'number:required' ] );

            expect( schema.isJoi ).to.be.true;
            expect( schema._type ).to.equal( 'alternatives' );

            expect( schema._inner.matches[0].schema._type ).to.equal( 'string' );
            expect( schema._inner.matches[0].schema._flags.presence ).to.equal( 'required' );

            expect( schema._inner.matches[1].schema._type ).to.equal( 'number' );
            expect( schema._inner.matches[1].schema._flags.presence ).to.equal( 'required' );

            let result1 = joi.validate( '3952469a-1b45-4d5e-825c-e25ec8b57cf6', schema );
            expect( result1.error ).to.be.null;

            let result2 = joi.validate( 42, schema );
            expect( result2.error ).to.be.null;

            let result3 = joi.validate( 'forty-two', schema );
            expect( result3.error ).to.exist;
        });
    });
});
<|endoftext|>


<commit_before>var EventEmitter = require( 'events' ).EventEmitter,
	util = require( 'util' ),
	pckg = require( '../package.json' ),
	kafka = require( 'kafka-node' );

/**
 *
 * @param {Object} config Connection configuration.
 *
 * @constructor
 */
var KafkaConnector = function( config ) {

	this.name = pckg.name;
	this.version = pckg.version;

	this.isReady = false;
	this._topics = [];

	this._validateConfig( config );
	this._clientId = config.clientId || ( Math.random() * 10000000000000000000 ).toString( 36 );

	this._client = new kafka.Client( config.connectionString );
	this._producer = new kafka.Producer( this._client );
	this._consumer = new kafka.Consumer( this._client, [] );

	this._producer.on( 'ready', this._onReady.bind( this ) );
	this._producer.on( 'error', this._onError.bind( this ) );

	this._consumer.on( 'message', this._onMessage.bind( this ) );
	this._consumer.on( 'error', this._onError.bind( this ) );
	this._consumer.on( 'offsetOutOfRange', this._onError.bind( this ) );

}

util.inherits( KafkaConnector, EventEmitter );

/**
 * Unsubscribes a function as a listener for a topic.
 *
 * Often it makes sense to make only one subscription per topic to the messaging
 * middleware and use an eventemitter to notify multiple subscribers of updates
 * for the same topic. This however does mean that the message-connector
 * needs to keep track of the subscribers and unsubscribe from the messaging middleware
 * if all subscribers have unsubscribed
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.unsubscribe = function( topic, callback ) {
	var self = this;
	if ( this._hasNoListeners( topic ) ) {
		this._consumer.removeTopics( [ topic ], function( err, removed ) {
			if ( err ) {
				self._onError( err );
			}
		} );
	} else {
		this.removeListener( topic, callback );
	}
}

/**
 * Adds a function as a listener for a topic.
 *
 * If the topic doesn't exist to be added, it will be created, then
 * added.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.subscribe = function( topic, callback ) {
	var self = this;
	if ( this._hasNoListeners( topic ) ) {
		this._tryAdd( topic, function( err, added ) {
			if ( err ) {
				this._onError( err );
			}
			if ( added ) {
				self.on( topic, callback );
			}
		} );
	} else {
		this.on( topic, callback );
	}
}

/**
 * Publishes a deepstream message on a topic
 *
 * Given a deepstream message of:
 * {
 * 		topic: 'R',
 * 		action: 'P',
 * 		data: [ 'user-54jcvew34', 32, 'zip', 'SE34JN' ]
 * }
 *
 * a clientId 75783 and a topic 'topic1', it publishes the following payload:
 *
 * {
 *      topic: 'topic1',
 *      messages: '{
 *          "data": {
 *              "topic":"R",
 *              "action":"P",
 *              "data":["user-54jcvew34",32,"zip","SE34JN"]},
 *              "_s":75783
 *      }'
 * }
 *
 * @param   {String}   topic
 * @param   {Object}   message
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.publish = function( topic, message ) {
	var self = this;
	var payload = {
		topic: topic,
		messages: JSON.stringify( {
			data: message,
			_s: this._clientId
		} )
	}
	this._trySend( payload, function( err ) {
		if ( err ) {
			self._onError( err );
		}
	} )
}

/**
 * Callback for incoming messages.
 *
 * Parses the message, removes _s (the sender Id) and emits if not sent from the same clientId.
 *
 * @param   {object}   message
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._onMessage = function( message ) {
	var parsedMessage;

	try {
		parsedMessage = JSON.parse( message.value.toString( 'utf-8' ) );
	} catch ( e ) {
		this.emit( 'error', 'message parse error ' + e.toString() );
	}

	if ( parsedMessage._s === this._clientId ) {
		return;
	}
	delete parsedMessage._s;
	this.emit( message.topic, parsedMessage.data );
}

KafkaConnector.prototype._onReady = function() {
	this.isReady = true;
	this.emit( 'ready' );
}

/**
 * Checks if this connector has any subscribers to [topic],
 * returns true if it does.
 *
 * @param   {string} topic
 *
 * @private
 * @returns {bool}
 */
KafkaConnector.prototype._hasNoListeners = function( topic ) {
	return this.listenerCount( topic ) == 0;
}

/**
 * Generic error callback.
 *
 * @param   {string}   err
 *
 * @returns {void}
 */
KafkaConnector.prototype._onError = function( err ) {
	this.emit( 'error', 'Kafka error: ' + err );
}

/**
 * Tries to add a topic to the consumer, creates it if
 * it doesn't exist, then adds it.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._tryAdd = function( topic, callback ) {
	var self = this;
	this._consumer.addTopics( [ topic ], function( err, added ) {
		if ( err ) {
			var matchingErrMsg = 'The topic(s) ' + topic + ' do not exist';
			if ( err.message.indexOf( matchingErrMsg ) > -1 ) {
				// When adding a topic to a consumer and the topic
				// does not exist, we'll get a 'The topic(s) [topic] do not exist'
				// error. Need to create topic then add it.
				self._createTopic( topic, function( err, created ) {
					if ( err ) {
						callback( err, created );
					}
					if ( created ) {
						self._tryAdd( topic, callback );
					}
				} );
			} else {
				// something else went wrong
				callback( err, added );
			}
		}
		if ( added ) {
			callback( err, added );
		}
	} );
}

/**
 * Tries to send a topic, creates it if it doesn't exist, then
 * sends it.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._trySend = function( payload, callback ) {
	var self = this;
	this._producer.send( [ payload ], function( err, data ) {
		if ( err ) {
			if ( err.indexOf( 'LeaderNotAvailable' ) > -1 ) {
				// If the topic doesn't exist when sending a payload we'll get a
				// LeaderNotAvailable error. This block creates the topic async
				// then sends the payload.
				self._createTopic( payload.topic, function( err, created ) {
					if ( err ) {
						callback( err );
					}
					if ( created ) {
						self._trySend( payload, callback );
					}
				} );
			} else {
				//something else went wrong
				callback( err );
			}
		}
	} );
}

/**
 * Creates a topic if it doesn't exist.
 *
 * Allows passing back of err or data to callback.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._createTopic = function( topic, callback ) {
	this._producer.createTopics( [ topic ], function( err, data ) {
		callback( err, data );
	} );
}

/**
 * Checks that the config has a connectionString key.
 *
 * @param   {Object} config
 *
 * @private
 * @returns {void}
 */
KafkaConnector.prototype._validateConfig = function( config ) {
	if ( typeof config.connectionString !== 'string' ) {
		throw new Error( 'Missing config parameter "connectionString"' );
	}
}

module.exports = KafkaConnector;<commit_msg>fixing docs<commit_after>var EventEmitter = require( 'events' ).EventEmitter,
	util = require( 'util' ),
	pckg = require( '../package.json' ),
	kafka = require( 'kafka-node' );

/**
 *
 * @param {Object} config Connection configuration.
 *
 * @constructor
 */
var KafkaConnector = function( config ) {

	this.name = pckg.name;
	this.version = pckg.version;

	this.isReady = false;
	this._topics = [];

	this._validateConfig( config );
	this._clientId = config.clientId || ( Math.random() * 10000000000000000000 ).toString( 36 );

	this._client = new kafka.Client( config.connectionString );
	this._producer = new kafka.Producer( this._client );
	this._consumer = new kafka.Consumer( this._client, [] );

	this._producer.on( 'ready', this._onReady.bind( this ) );
	this._producer.on( 'error', this._onError.bind( this ) );

	this._consumer.on( 'message', this._onMessage.bind( this ) );
	this._consumer.on( 'error', this._onError.bind( this ) );
	this._consumer.on( 'offsetOutOfRange', this._onError.bind( this ) );

}

util.inherits( KafkaConnector, EventEmitter );

/**
 * Unsubscribes a function as a listener for a topic.
 *
 * Often it makes sense to make only one subscription per topic to the messaging
 * middleware and use an eventemitter to notify multiple subscribers of updates
 * for the same topic. This however does mean that the message-connector
 * needs to keep track of the subscribers and unsubscribe from the messaging middleware
 * if all subscribers have unsubscribed
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.unsubscribe = function( topic, callback ) {
	var self = this;
	if ( this._hasNoListeners( topic ) ) {
		this._consumer.removeTopics( [ topic ], function( err, removed ) {
			if ( err ) {
				self._onError( err );
			}
		} );
	} else {
		this.removeListener( topic, callback );
	}
}

/**
 * Adds a function as a listener for a topic.
 *
 * If the topic doesn't exist to be added, it will be created, then
 * added.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.subscribe = function( topic, callback ) {
	var self = this;
	if ( this._hasNoListeners( topic ) ) {
		this._tryAdd( topic, function( err, added ) {
			if ( err ) {
				this._onError( err );
			}
			if ( added ) {
				self.on( topic, callback );
			}
		} );
	} else {
		this.on( topic, callback );
	}
}

/**
 * Publishes a deepstream message on a topic
 *
 * Given a deepstream message of:
 * {
 * 		topic: 'R',
 * 		action: 'P',
 * 		data: [ 'user-54jcvew34', 32, 'zip', 'SE34JN' ]
 * }
 *
 * a clientId 75783 and a topic 'topic1', it publishes the following payload:
 *
 * {
 *      topic: 'topic1',
 *      messages: '{
 *          "data": {
 *              "topic":"R",
 *              "action":"P",
 *              "data":["user-54jcvew34",32,"zip","SE34JN"]},
 *              "_s":75783
 *      }'
 * }
 *
 * @param {
    String
 }
 topic
 * @param   {Object}   message
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype.publish = function( topic, message ) {
	var self = this;
	var payload = {
		topic: topic,
		messages: JSON.stringify( {
			data: message,
			_s: this._clientId
		} )
	}
	this._trySend( payload, function( err ) {
		if ( err ) {
			self._onError( err );
		}
	} )
}

/**
 * Callback for incoming messages.
 *
 * Parses the message, removes _s (the sender Id) and emits if not sent from the same clientId.
 *
 * @param   {object}   message
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._onMessage = function( message ) {
	var parsedMessage;

	try {
		parsedMessage = JSON.parse( message.value.toString( 'utf-8' ) );
	} catch ( e ) {
		this.emit( 'error', 'message parse error ' + e.toString() );
	}

	if ( parsedMessage._s === this._clientId ) {
		return;
	}
	delete parsedMessage._s;
	this.emit( message.topic, parsedMessage.data );
}

KafkaConnector.prototype._onReady = function() {
	this.isReady = true;
	this.emit( 'ready' );
}

/**
 * Checks if this connector has any subscribers to [topic],
 * returns true if it does.
 *
 * @param   {string} topic
 *
 * @private
 * @returns {bool}
 */
KafkaConnector.prototype._hasNoListeners = function( topic ) {
	return this.listenerCount( topic ) == 0;
}

/**
 * Generic error callback.
 *
 * @param   {string}   err
 *
 * @returns {void}
 */
KafkaConnector.prototype._onError = function( err ) {
	this.emit( 'error', 'Kafka error: ' + err );
}

/**
 * Tries to add a topic to the consumer, creates it if
 * it doesn't exist, then adds it.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._tryAdd = function( topic, callback ) {
	var self = this;
	this._consumer.addTopics( [ topic ], function( err, added ) {
		if ( err ) {
			var matchingErrMsg = 'The topic(s) ' + topic + ' do not exist';
			if ( err.message.indexOf( matchingErrMsg ) > -1 ) {
				// When adding a topic to a consumer and the topic
				// does not exist, we'll get a 'The topic(s) [topic] do not exist'
				// error. Need to create topic then add it.
				self._createTopic( topic, function( err, created ) {
					if ( err ) {
						callback( err, created );
					}
					if ( created ) {
						self._tryAdd( topic, callback );
					}
				} );
			} else {
				// something else went wrong
				callback( err, added );
			}
		}
		if ( added ) {
			callback( err, added );
		}
	} );
}

/**
 * Tries to send a topic, creates it if it doesn't exist, then
 * sends it.
 *
 * @param   {Object}   payload
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._trySend = function( payload, callback ) {
	var self = this;
	this._producer.send( [ payload ], function( err, data ) {
		if ( err ) {
			if ( err.indexOf( 'LeaderNotAvailable' ) > -1 ) {
				// If the topic doesn't exist when sending a payload we'll get a
				// LeaderNotAvailable error. This block creates the topic async
				// then sends the payload.
				self._createTopic( payload.topic, function( err, created ) {
					if ( err ) {
						callback( err );
					}
					if ( created ) {
						self._trySend( payload, callback );
					}
				} );
			} else {
				//something else went wrong
				callback( err );
			}
		}
	} );
}

/**
 * Creates a topic if it doesn't exist.
 *
 * Allows passing back of err or data to callback.
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
KafkaConnector.prototype._createTopic = function( topic, callback ) {
	this._producer.createTopics( [ topic ], function( err, data ) {
		callback( err, data );
	} );
}

/**
 * Checks that the config has a connectionString key.
 *
 * @param   {Object} config
 *
 * @private
 * @returns {void}
 */
KafkaConnector.prototype._validateConfig = function( config ) {
	if ( typeof config.connectionString !== 'string' ) {
		throw new Error( 'Missing config parameter "connectionString"' );
	}
}

module.exports = KafkaConnector;<|endoftext|>


<commit_before>import Ember from 'ember';
import {
  moduleForComponent,
  test
} from 'ember-qunit';
import FlashMessage from 'ember-cli-flash/flash/object';

const {
  run,
  get,
  set
} = Ember;
let flash;

moduleForComponent('flash-message', 'FlashMessageComponent', {
  unit: true,

  beforeEach() {
    flash = FlashMessage.create({
      message: 'test',
      type: 'test',
      timeout: 50,
      extendedTimeout: 5000,
      showProgress: true
    });
  },

  afterEach() {
    run(() => {
      flash.destroy();
    });

    flash = null;
  }
});

test('it renders with the right props', function(assert) {
  assert.expect(5);

  const component = this.subject({ flash });
  assert.equal(get(component, 'active'), false, 'it initializes with `active` set to false');

  this.render();
  assert.equal(get(component, 'alertType'), 'alert alert-test', 'it has the right `alertType`');
  assert.equal(get(component, 'flashType'), 'Test', 'it has the right `flashType`');
  assert.equal(get(component, 'progressDuration'), `transition-duration: ${flash.get('timeout')}ms`, 'it has the right `progressDuration`');

  run.next(() => {
    assert.equal(get(component, 'active'), true, 'it sets `active` to true after rendering');
  });
});

test('exiting the flash object sets exiting on the component', function(assert) {
  assert.expect(2);

  const component = this.subject({ flash });
  this.render();
  assert.equal(get(component, 'exiting'), false, 'it initializes with `exiting` set to false');

  run(() => {
    set(flash, 'exiting' , true);
    assert.ok(get(component, 'exiting'), 'it sets `exiting` to true when the flash object is exiting');
  });
});

test('it destroys the flash object on click', function(assert) {
  assert.expect(1);
  const component = this.subject({ flash });
  this.render();

  $('.alert').click();
  assert.ok(get(component, 'flash').isDestroyed, 'it destroys the flash object on click');
});

test('it does not destroy the flash object when `flash.destroyOnClick` is false', function(assert) {
  assert.expect(1);
  flash.destroyOnClick = false;
  const component = this.subject({ flash });
  this.render();

  $('.alert').click();
  assert.notOk(get(component, 'flash').isDestroyed, 'it does not destroy the flash object on click');
});
<commit_msg>remove flash.destroy as it fails on latest builds of Ember (#218)<commit_after>import Ember from 'ember';
import {
  moduleForComponent,
  test
} from 'ember-qunit';
import FlashMessage from 'ember-cli-flash/flash/object';

const {
  run,
  get,
  set
} = Ember;
let flash;

moduleForComponent('flash-message', 'FlashMessageComponent', {
  unit: true,

  beforeEach() {
    flash = FlashMessage.create({
      message: 'test',
      type: 'test',
      timeout: 50,
      extendedTimeout: 5000,
      showProgress: true
    });
  },

  afterEach() {
    flash = null;
  }
});

test('it renders with the right props', function(assert) {
  assert.expect(5);

  const component = this.subject({ flash });
  assert.equal(get(component, 'active'), false, 'it initializes with `active` set to false');

  this.render();
  assert.equal(get(component, 'alertType'), 'alert alert-test', 'it has the right `alertType`');
  assert.equal(get(component, 'flashType'), 'Test', 'it has the right `flashType`');
  assert.equal(get(component, 'progressDuration'), `transition-duration: ${flash.get('timeout')}ms`, 'it has the right `progressDuration`');

  run.next(() => {
    assert.equal(get(component, 'active'), true, 'it sets `active` to true after rendering');
  });
});

test('exiting the flash object sets exiting on the component', function(assert) {
  assert.expect(2);

  const component = this.subject({ flash });
  this.render();
  assert.equal(get(component, 'exiting'), false, 'it initializes with `exiting` set to false');

  run(() => {
    set(flash, 'exiting' , true);
    assert.ok(get(component, 'exiting'), 'it sets `exiting` to true when the flash object is exiting');
  });
});

test('it destroys the flash object on click', function(assert) {
  assert.expect(1);
  const component = this.subject({ flash });
  this.render();

  $('.alert').click();
  assert.ok(get(component, 'flash').isDestroyed, 'it destroys the flash object on click');
});

test('it does not destroy the flash object when `flash.destroyOnClick` is false', function(assert) {
  assert.expect(1);
  flash.destroyOnClick = false;
  const component = this.subject({ flash });
  this.render();

  $('.alert').click();
  assert.notOk(get(component, 'flash').isDestroyed, 'it does not destroy the flash object on click');
});
<|endoftext|>