<commit_before>var _ = require("lodash"),
    Sequelize = require("sequelize"),
    SequelizeG = require("./index.js"),
    assert = require("assert"),
    when = require("when");

var sequelize = new Sequelize("myapp_test",
    "travis",
    "", {
        dialect: "mysql",
        logging: false
    });

describe("Sequelize generator", function () {
    "use strict";

    var sync = function () {
        return sequelize.getQueryInterface().dropAllTables().then(function () {
            return sequelize.sync({
                force: true
            });
        });
    };

    it("should instantiate a model without relationships", function (done) {
        var ModelWithoutRelationship = sequelize.define("modelWithoutRelationship", {});

        sync().then(function () {
            return new SequelizeG(ModelWithoutRelationship).then(function (modelChild) {
                assert.ok(modelChild.daoFactoryName === ModelWithoutRelationship.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the parent it belongs to", function (done) {
        var ModelParent = sequelize.define("ModelParent", {}),
            ModelChild = sequelize.define("ModelChild", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the multiple parents it belongs to", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            parentModels = new Array(10),
            parentModelsLength = parentModels.length;

        for (var i = 0; i < parentModelsLength; i++) {
            var ModelParent = sequelize.define("ModelParent" + i, {});

            parentModels[i] = ModelParent;

            ModelChild.belongsTo(ModelParent);
        }

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return when.all(parentModels.map(function (ParentModel, i) {
                    return child["getModelParent" + i]().then(function (parentI) {
                        assert.ok(parentI.daoFactoryName === parentModels[i].name);

                        return i; // Used as a counter on the length assert below
                    });
                }));
            });
        }).then(function (is) {
            assert.equal(parentModelsLength, is.length);
            done();
        }, done);
    });

    it("should instantiate a child model, its parent, and its grandparent", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(parent.daoFactoryName === ModelParent.name);

                    return parent;
                });
            }).then(function (parent) {
                return parent.getModelGrandParent().then(function (grandParent) {
                    assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
                });
            });
        }).then(done, done);
    });

    it("should instantiate a child model, and several of its ancestor generations", function (done) {
        var modelsGenerations = [sequelize.define("Model0", {})],
            additionalModelsNumber = 9;

        for (var i = 1; i < additionalModelsNumber + 1; i++) {
            var Model = sequelize.define("Model" + i, {}),
                previousModel = modelsGenerations[i - 1];

            modelsGenerations[i] = Model;

            previousModel.belongsTo(Model);
        }

        sync().then(function () {
            return new SequelizeG(modelsGenerations[0]).then(function (model0) {
                return when.reduce(modelsGenerations, function (currentResult, value, index, total) {
                    if (index < total - 1) {
                        assert.ok(currentResult.daoFactoryName === value.name);
                        return currentResult["getModel" + (index + 1)]();
                    } else {
                        return total;
                    }
                }, model0);
            });
        }).then(function (total) {
            assert.equal(additionalModelsNumber + 1, total);
            done();
        }, done);
    });

    it("should instantiate a child model, both parents, and 4 grandparents (paternal and maternal)", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelFather = sequelize.define("ModelFather", {}),
            ModelMother = sequelize.define("ModelMother", {}),
            ModelPaternalGrandFather = sequelize.define("ModelPaternalGrandFather", {}),
            ModelPaternalGrandMother = sequelize.define("ModelPaternalGrandMother", {}),
            ModelMaternalGrandFather = sequelize.define("ModelMaternalGrandFather", {}),
            ModelMaternalGrandMother = sequelize.define("ModelMaternalGrandMother", {});

        ModelChild.belongsTo(ModelFather);
        ModelChild.belongsTo(ModelMother);

        ModelFather.belongsTo(ModelPaternalGrandFather);
        ModelFather.belongsTo(ModelPaternalGrandMother);

        ModelMother.belongsTo(ModelMaternalGrandFather);
        ModelMother.belongsTo(ModelMaternalGrandMother);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                // Check father and paternal grandparents
                return child.getModelFather().then(function (father) {
                    assert.ok(father.daoFactoryName === ModelFather.name);
                    return father.getModelPaternalGrandFather().then(function (paternalGrandFather) {
                        assert.ok(paternalGrandFather.daoFactoryName === ModelPaternalGrandFather.name);

                        return father.getModelPaternalGrandMother();
                    }).then(function (paternalGrandMother) {
                        assert.ok(paternalGrandMother.daoFactoryName === ModelPaternalGrandMother.name);

                        return child;
                    });
                }).then(function (child) {
                    // Check mother and maternal grandparents
                    return child.getModelMother().then(function (mother) {
                        assert.ok(mother.daoFactoryName === ModelMother.name);
                        return mother.getModelMaternalGrandFather().then(function (maternalGrandFather) {
                            assert.ok(maternalGrandFather.daoFactoryName === ModelMaternalGrandFather.name);

                            return mother.getModelMaternalGrandMother();
                        }).then(function (maternalGrandMother) {
                            assert.ok(maternalGrandMother.daoFactoryName === ModelMaternalGrandMother.name);

                            return null;
                        });
                    });
                });
            });
        }).then(done, done);
    });

    it("should set attributes for Model", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING,
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    name: "Julio Nobrega Netto"
                }
            }).then(function (child) {
                assert.equal(child.name, "Julio Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for parent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelParent: {
                    attributes: {
                        name: "José Nobrega Netto"
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.name, "José Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for grandparent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelGrandParent: {
                    attributes: {
                        name: "Julio Nobrega" // notice the lack of Netto
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                return parent.getModelGrandParent();
            }).then(function (grandParent) {
                assert.equal(grandParent.name, "Julio Nobrega");
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on child model", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isNumber(instance.number));
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on parent models", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(_.isNumber(parent.number));
            });
        }).then(done, done);
    });

    it("should not populate INTEGER data type field on child and parents if set as attributes", function (done) {
        var childNumber = _.uniqueId(),
            parentNumber = _.uniqueId(),
            ModelChild = sequelize.define("ModelChild", {
                number: Sequelize.INTEGER
            }),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                attributes: {
                    number: childNumber
                },
                ModelParent: {
                    attributes: {
                        number: parentNumber
                    }
                }
            }).then(function (child) {
                assert.equal(child.number, childNumber);
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.number, parentNumber);
            });
        }).then(done, done);
    });

    it("should populate fields when the column is specified as an object", function (done) {
        var Model = sequelize.define("Model", {
            number1: Sequelize.INTEGER,
            number2: {
                type: Sequelize.INTEGER
            }
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (model) {
                assert.ok(_.isNumber(model.number1));
                assert.ok(_.isNumber(model.number2));
            });
        }).then(done, done);
    });

    it("should populate field with null if specified as an attribute", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    number: null
                }
            }).then(function (model) {
                assert.ok(_.isNull(model.number));
            });
        }).then(done, done);
    });

    it("should accept as an attribute a foreign key of an already created instance", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return ModelParent.create();
        }).then(function (parent) {
            return new SequelizeG(ModelChild, {
                attributes: {
                    ModelParentId: parent.id
                }
            }).then(function (child) {
                assert.equal(parent.id, child.ModelParentId);
            });
        }).then(done, done);
    });

    it("should set a foreign key to a random, already created record, if option is set", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            var chainer = new Sequelize.Utils.QueryChainer();

            _.times(3, function () {
                chainer.add(ModelParent.create());
            });

            return chainer.run();
        }).then(function (parents) {
            var parentIds = _.pluck(parents, "id");

            return new SequelizeG(ModelChild, {
                ModelParent: "any"
            }).then(function (child) {
                assert.ok(_.contains(parentIds, child.ModelParentId));
            });
        }).then(done, done);
    });

    it("should create record with NULL on fields that reference parents when foreignKeyConstraint is true", function (done) {
        // Only the creation gets NULL. SequelizeG later calls instance.setModelParent(parentInstance) which will
        // replace NULL by parentInstance primary key
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKeyConstraint: true
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(child.ModelParentId === parent.id);
                    assert.ok(parent.daoFactoryName === ModelParent.name);
                });
            });
        }).then(done, done);
    });

    it("should populate ENUM data type fields with any value from its possible values", function (done) {
        var possibleValues = ["Julio", "José"],
            ModelChild = sequelize.define("ModelChild", {
                name: {
                    type: Sequelize.ENUM,
                    values: possibleValues
                }
            });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                assert.ok(_.contains(possibleValues, child.name));
            });
        }).then(done, done);
    });

    it("should populate STRING data type fields with random string", function (done) {
        var ModelChild = sequelize.define("ModelChild", {
            name: Sequelize.STRING
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                assert.ok(_.isString(child.name));
                assert.ok(child.name.length > 0);
            });
        }).then(done, done);
    });

    it("should populate STRING(n) data type fields with random string", function (done) {
        var ModelChild = sequelize.define("ModelChild", {
            name: Sequelize.STRING(42)
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                assert.ok(_.isString(child.name));
                assert.ok(child.name.length > 0);
            });
        }).then(done, done);
    });

    it("should set parent model when association has \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {
            name: Sequelize.STRING(42)
        }),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                assert.ok(_.isString(child.name));
                assert.ok(child.name.length > 0);
            });
        }).then(done, done);
    });
});
<commit_msg>Improved naming of models<commit_after>var _ = require("lodash"),
    Sequelize = require("sequelize"),
    SequelizeG = require("./index.js"),
    assert = require("assert"),
    when = require("when");

var sequelize = new Sequelize("myapp_test",
    "travis",
    "", {
        dialect: "mysql",
        logging: false
    });

describe("Sequelize generator", function () {
    "use strict";

    var sync = function () {
        return sequelize.getQueryInterface().dropAllTables().then(function () {
            return sequelize.sync({
                force: true
            });
        });
    };

    it("should instantiate a model without relationships", function (done) {
        var ModelWithoutRelationship = sequelize.define("modelWithoutRelationship", {});

        sync().then(function () {
            return new SequelizeG(ModelWithoutRelationship).then(function (modelChild) {
                assert.ok(modelChild.daoFactoryName === ModelWithoutRelationship.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the parent it belongs to", function (done) {
        var ModelParent = sequelize.define("ModelParent", {}),
            ModelChild = sequelize.define("ModelChild", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(parent.daoFactoryName === ModelParent.name);
            });
        }).then(done, done);
    });

    it("should instantiate a child model and automatically the multiple parents it belongs to", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            parentModels = new Array(10),
            parentModelsLength = parentModels.length;

        for (var i = 0; i < parentModelsLength; i++) {
            var ModelParent = sequelize.define("ModelParent" + i, {});

            parentModels[i] = ModelParent;

            ModelChild.belongsTo(ModelParent);
        }

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return when.all(parentModels.map(function (ParentModel, i) {
                    return child["getModelParent" + i]().then(function (parentI) {
                        assert.ok(parentI.daoFactoryName === parentModels[i].name);

                        return i; // Used as a counter on the length assert below
                    });
                }));
            });
        }).then(function (is) {
            assert.equal(parentModelsLength, is.length);
            done();
        }, done);
    });

    it("should instantiate a child model, its parent, and its grandparent", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {});

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(parent.daoFactoryName === ModelParent.name);

                    return parent;
                });
            }).then(function (parent) {
                return parent.getModelGrandParent().then(function (grandParent) {
                    assert.ok(grandParent.daoFactoryName === ModelGrandParent.name);
                });
            });
        }).then(done, done);
    });

    it("should instantiate a child model, and several of its ancestor generations", function (done) {
        var modelsGenerations = [sequelize.define("Model0", {})],
            additionalModelsNumber = 9;

        for (var i = 1; i < additionalModelsNumber + 1; i++) {
            var Model = sequelize.define("Model" + i, {}),
                previousModel = modelsGenerations[i - 1];

            modelsGenerations[i] = Model;

            previousModel.belongsTo(Model);
        }

        sync().then(function () {
            return new SequelizeG(modelsGenerations[0]).then(function (model0) {
                return when.reduce(modelsGenerations, function (currentResult, value, index, total) {
                    if (index < total - 1) {
                        assert.ok(currentResult.daoFactoryName === value.name);
                        return currentResult["getModel" + (index + 1)]();
                    } else {
                        return total;
                    }
                }, model0);
            });
        }).then(function (total) {
            assert.equal(additionalModelsNumber + 1, total);
            done();
        }, done);
    });

    it("should instantiate a child model, both parents, and 4 grandparents (paternal and maternal)", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelFather = sequelize.define("ModelFather", {}),
            ModelMother = sequelize.define("ModelMother", {}),
            ModelPaternalGrandFather = sequelize.define("ModelPaternalGrandFather", {}),
            ModelPaternalGrandMother = sequelize.define("ModelPaternalGrandMother", {}),
            ModelMaternalGrandFather = sequelize.define("ModelMaternalGrandFather", {}),
            ModelMaternalGrandMother = sequelize.define("ModelMaternalGrandMother", {});

        ModelChild.belongsTo(ModelFather);
        ModelChild.belongsTo(ModelMother);

        ModelFather.belongsTo(ModelPaternalGrandFather);
        ModelFather.belongsTo(ModelPaternalGrandMother);

        ModelMother.belongsTo(ModelMaternalGrandFather);
        ModelMother.belongsTo(ModelMaternalGrandMother);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                // Check father and paternal grandparents
                return child.getModelFather().then(function (father) {
                    assert.ok(father.daoFactoryName === ModelFather.name);
                    return father.getModelPaternalGrandFather().then(function (paternalGrandFather) {
                        assert.ok(paternalGrandFather.daoFactoryName === ModelPaternalGrandFather.name);

                        return father.getModelPaternalGrandMother();
                    }).then(function (paternalGrandMother) {
                        assert.ok(paternalGrandMother.daoFactoryName === ModelPaternalGrandMother.name);

                        return child;
                    });
                }).then(function (child) {
                    // Check mother and maternal grandparents
                    return child.getModelMother().then(function (mother) {
                        assert.ok(mother.daoFactoryName === ModelMother.name);
                        return mother.getModelMaternalGrandFather().then(function (maternalGrandFather) {
                            assert.ok(maternalGrandFather.daoFactoryName === ModelMaternalGrandFather.name);

                            return mother.getModelMaternalGrandMother();
                        }).then(function (maternalGrandMother) {
                            assert.ok(maternalGrandMother.daoFactoryName === ModelMaternalGrandMother.name);

                            return null;
                        });
                    });
                });
            });
        }).then(done, done);
    });

    it("should set attributes for Model", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING,
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    name: "Julio Nobrega Netto"
                }
            }).then(function (child) {
                assert.equal(child.name, "Julio Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for parent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelParent: {
                    attributes: {
                        name: "José Nobrega Netto"
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.name, "José Nobrega Netto");
            });
        }).then(done, done);
    });

    it("should set attributes for grandparent model", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {}),
            ModelGrandParent = sequelize.define("ModelGrandParent", {
                name: Sequelize.STRING,
            });

        ModelChild.belongsTo(ModelParent);
        ModelParent.belongsTo(ModelGrandParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                ModelGrandParent: {
                    attributes: {
                        name: "Julio Nobrega" // notice the lack of Netto
                    }
                }
            }).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                return parent.getModelGrandParent();
            }).then(function (grandParent) {
                assert.equal(grandParent.name, "Julio Nobrega");
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on child model", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isNumber(instance.number));
            });
        }).then(done, done);
    });

    it("should populate INTEGER data type fields with integers on parent models", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent();
            }).then(function (parent) {
                assert.ok(_.isNumber(parent.number));
            });
        }).then(done, done);
    });

    it("should not populate INTEGER data type field on child and parents if set as attributes", function (done) {
        var childNumber = _.uniqueId(),
            parentNumber = _.uniqueId(),
            ModelChild = sequelize.define("ModelChild", {
                number: Sequelize.INTEGER
            }),
            ModelParent = sequelize.define("ModelParent", {
                number: Sequelize.INTEGER
            });

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return new SequelizeG(ModelChild, {
                attributes: {
                    number: childNumber
                },
                ModelParent: {
                    attributes: {
                        number: parentNumber
                    }
                }
            }).then(function (child) {
                assert.equal(child.number, childNumber);
                return child.getModelParent();
            }).then(function (parent) {
                assert.equal(parent.number, parentNumber);
            });
        }).then(done, done);
    });

    it("should populate fields when the column is specified as an object", function (done) {
        var Model = sequelize.define("Model", {
            number1: Sequelize.INTEGER,
            number2: {
                type: Sequelize.INTEGER
            }
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (model) {
                assert.ok(_.isNumber(model.number1));
                assert.ok(_.isNumber(model.number2));
            });
        }).then(done, done);
    });

    it("should populate field with null if specified as an attribute", function (done) {
        var Model = sequelize.define("Model", {
            number: Sequelize.INTEGER
        });

        sync().then(function () {
            return new SequelizeG(Model, {
                attributes: {
                    number: null
                }
            }).then(function (model) {
                assert.ok(_.isNull(model.number));
            });
        }).then(done, done);
    });

    it("should accept as an attribute a foreign key of an already created instance", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            return ModelParent.create();
        }).then(function (parent) {
            return new SequelizeG(ModelChild, {
                attributes: {
                    ModelParentId: parent.id
                }
            }).then(function (child) {
                assert.equal(parent.id, child.ModelParentId);
            });
        }).then(done, done);
    });

    it("should set a foreign key to a random, already created record, if option is set", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent);

        sync().then(function () {
            var chainer = new Sequelize.Utils.QueryChainer();

            _.times(3, function () {
                chainer.add(ModelParent.create());
            });

            return chainer.run();
        }).then(function (parents) {
            var parentIds = _.pluck(parents, "id");

            return new SequelizeG(ModelChild, {
                ModelParent: "any"
            }).then(function (child) {
                assert.ok(_.contains(parentIds, child.ModelParentId));
            });
        }).then(done, done);
    });

    it("should create record with NULL on fields that reference parents when foreignKeyConstraint is true", function (done) {
        // Only the creation gets NULL. SequelizeG later calls instance.setModelParent(parentInstance) which will
        // replace NULL by parentInstance primary key
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKeyConstraint: true
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                return child.getModelParent().then(function (parent) {
                    assert.ok(child.ModelParentId === parent.id);
                    assert.ok(parent.daoFactoryName === ModelParent.name);
                });
            });
        }).then(done, done);
    });

    it("should populate ENUM data type fields with any value from its possible values", function (done) {
        var possibleValues = ["Julio", "José"],
            Model = sequelize.define("Model", {
                name: {
                    type: Sequelize.ENUM,
                    values: possibleValues
                }
            });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.contains(possibleValues, instance.name));
            });
        }).then(done, done);
    });

    it("should populate STRING data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should populate STRING(n) data type fields with random string", function (done) {
        var Model = sequelize.define("Model", {
            name: Sequelize.STRING(42)
        });

        sync().then(function () {
            return new SequelizeG(Model).then(function (instance) {
                assert.ok(_.isString(instance.name));
                assert.ok(instance.name.length > 0);
            });
        }).then(done, done);
    });

    it("should set parent model when association has \"as\" option", function (done) {
        var ModelChild = sequelize.define("ModelChild", {}),
            ModelParent = sequelize.define("ModelParent", {});

        ModelChild.belongsTo(ModelParent, {
            foreignKey: "ModelParentId",
            as: "someName"
        });

        sync().then(function () {
            return new SequelizeG(ModelChild).then(function (child) {
                assert.ok(_.isString(child.name));
                assert.ok(child.name.length > 0);
            });
        }).then(done, done);
    });
});
<|endoftext|>


<commit_before>const moment = require('moment');
const api = require('../api');
const _ = require('lodash');

/**
 * Generates the iso-weekday abbreviation for a given number, e.g. for the Schul-Cloud Calendar-Service
 * @param weekdayNum {number}
 * @returns {string} - abbreviation of weekday
 */
const getIsoWeekdayForNumber = (weekdayNum) => {
	let weekdayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'];
	return weekdayNames[weekdayNum];
};

/**
 * Generates the fullcalendar.js weekday index of a given iso weekday label
 * @param weekday {string}
 * @returns {number} - number of weekday
 */
const getNumberForFullCalendarWeekday = (weekday) => {
	let weekdayNames = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
	return weekdayNames.indexOf(weekday);
};

/**
 *  Generates the german weekday label for a given number
 * @param weekdayNum {number}
 * @returns {string} - abbreviation of weekday
 */
const getWeekdayForNumber = (weekdayNum) => {
	let weekdayNames = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
	return weekdayNames[weekdayNum];
};

/**
 * Generates the index of a given german weekday label
 * @param weekday {string}
 * @returns {number} - number of weekday
 */
const getNumberForWeekday = (weekday) => {
	let weekdayNames = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
	return weekdayNames.indexOf(weekday);
};

/**
 * Creates recurring (weekly) events for a @param recurringEvent definition
 * @param recurringEvent {Event} - the recurring (weekly) event
 * @return recurringEvents [] - new set of events
 */
const createRecurringEvents = (recurringEvent) => {
	let recurringEvents = [];
	let start = recurringEvent.start;
	let until = new Date(recurringEvent.included[0].attributes.until).getTime();
	let end = recurringEvent.end;
	let oneDayIndicator = 24 * 60 * 60 * 1000;
	let oneWeekIndicator = 7 * oneDayIndicator;

	// find first weekday, if the start-event is not a real weekly event itself, because it's just a period of time
	for (var i = 0; start + i * oneDayIndicator <= end + oneWeekIndicator; i++) {
		let newStartDate = start + i * oneDayIndicator;
		let newEndDate = end + i * oneDayIndicator;

		// check if it is the given weekday, if so set first date of recurring events
		if (moment(newStartDate).day() == getNumberForFullCalendarWeekday(recurringEvent.included[0].attributes.wkst)) {
			start = newStartDate;
			end = newEndDate;
			break;
		}
	}

	// loop over all new weekdays from startDate to untilDate
	for (i = 0; start + i * oneWeekIndicator <= until; i++) {

		let newStartDate = start + i * oneWeekIndicator;
		let newEndDate = end + i * oneWeekIndicator;

		recurringEvents.push({
			title: recurringEvent.summary,
			summary: recurringEvent.summary,
			location: recurringEvent.location,
			description: recurringEvent.description,
			url: recurringEvent.url,
			color: recurringEvent.color,
			start: newStartDate,
			end: newEndDate
		});

	}

	return recurringEvents;
};

/**
 * handle recurring events for calendar
 * @param event {Event} - a event which could contain a recurring value
 * @returns events [] - new set of events
 */
const mapRecurringEvent = (event) => {
	if (event.included && event.included[0].attributes.freq == 'WEEKLY') {
		return createRecurringEvents(event);
	}

	return [event];
};

/**
 * maps properties of a event to fit calendar, e.g. url and color
 * If any error is accoured then return course or team with default color.
 * @param event
 */
const mapEventProps = (event, req) => {
	if (event['x-sc-courseId']) {
		return api(req).get(`/courses/${event['x-sc-courseId']}`).then((course) => {
			event.url = event['x-sc-courseTimeId'] ? `/courses/${course._id}` : '';
			event.color = course.color;
			return event;
		}).catch((err) => {
			// eslint-disable-next-line no-console
			console.log("event['x-sc-courseId']", err);
			event.url = '';
			event.color = '#ff0000';
			return event;
		});
	}

	if (event['x-sc-teamId']) {
		return api(req).get(`/teams/${event['x-sc-teamId']}`).then((team) => {
			event.url = '';
			event.color = team.color;
			return event;
		}).catch((err) => {
			// eslint-disable-next-line no-console
			console.log("event['x-sc-teamId']", err);
			event.url = '';
			event.color = '#ff0000';
			return event;
		});
	}

	return event;
};

/**
 * retrieves the next date for given weekly courseTimes
 * @param courseTimes - the times of a course
 * @return {String} - a formatted date string
 */
const getNextEventForCourseTimes = (courseTimes) => {
	if ((courseTimes || []).length <= 0) return;
	const nextDates = _.map(courseTimes, (ct) => {
		let weekDayIdentifier = ct.weekday + 1; // moment starts on sunday

		// if current week's weekday is over, take the one next week
		if (moment().day() > weekDayIdentifier) weekDayIdentifier += 7;

		// return nothing if date has already passed
		const date = moment().day(weekDayIdentifier).hours(0).minutes(0)
			.seconds(0)
			.milliseconds(ct.startTime);
		if (date.isBefore()) return;

		// has to store index, because .indexOf with moment arrays does not work
		// eslint-disable-next-line consistent-return
		return date;
	});

	// find nearest day from now
	const minDate = _.min(nextDates);
	// eslint-disable-next-line consistent-return
	return moment(minDate).format('DD.MM.YYYY HH:mm');
};

if (!Date.prototype.toLocalISOString) {
	(function() {

		function pad(number) {
			if (number < 10) {
				return '0' + number;
			}
			return number;
		}

		Date.prototype.toLocalISOString = function() {
			return this.getFullYear() +
				'-' + pad(this.getMonth() + 1) +
				'-' + pad(this.getDate()) +
				'T' + pad(this.getHours()) +
				':' + pad(this.getMinutes()) +
				':' + pad(this.getSeconds()) +
				'.' + (this.getMilliseconds() / 1000).toFixed(3).slice(2, 5) +
				'Z';
		};

	}());
}

module.exports = {
	getIsoWeekdayForNumber,
	getWeekdayForNumber,
	getNumberForWeekday,
	getNumberForFullCalendarWeekday,
	createRecurringEvents,
	mapRecurringEvent,
	mapEventProps,
	getNextEventForCourseTimes
};<commit_msg>code refactoring<commit_after>const moment = require('moment');
const _ = require('lodash');
const api = require('../api');

/**
 * Generates the iso-weekday abbreviation for a given number, e.g. for the Schul-Cloud Calendar-Service
 * @param weekdayNum {number}
 * @returns {string} - abbreviation of weekday
 */
const getIsoWeekdayForNumber = (weekdayNum) => {
	const weekdayNames = ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'];
	return weekdayNames[weekdayNum];
};

/**
 * Generates the fullcalendar.js weekday index of a given iso weekday label
 * @param weekday {string}
 * @returns {number} - number of weekday
 */
const getNumberForFullCalendarWeekday = (weekday) => {
	const weekdayNames = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
	return weekdayNames.indexOf(weekday);
};

/**
 *  Generates the german weekday label for a given number
 * @param weekdayNum {number}
 * @returns {string} - abbreviation of weekday
 */
const getWeekdayForNumber = (weekdayNum) => {
	const weekdayNames = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
	return weekdayNames[weekdayNum];
};

/**
 * Generates the index of a given german weekday label
 * @param weekday {string}
 * @returns {number} - number of weekday
 */
const getNumberForWeekday = (weekday) => {
	const weekdayNames = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'];
	return weekdayNames.indexOf(weekday);
};

/**
 * Creates recurring (weekly) events for a @param recurringEvent definition
 * @param recurringEvent {Event} - the recurring (weekly) event
 * @return recurringEvents [] - new set of events
 */
const createRecurringEvents = (recurringEvent) => {
	const recurringEvents = [];
	let { start } = recurringEvent;
	const until = new Date(recurringEvent.included[0].attributes.until).getTime();
	let { end } = recurringEvent;
	const oneDayIndicator = 24 * 60 * 60 * 1000;
	const oneWeekIndicator = 7 * oneDayIndicator;

	// find first weekday, if the start-event is not a real weekly event itself, because it's just a period of time
	for (let i = 0; start + i * oneDayIndicator <= end + oneWeekIndicator; i += 1) {
		const newStartDate = start + i * oneDayIndicator;
		const newEndDate = end + i * oneDayIndicator;

		// check if it is the given weekday, if so set first date of recurring events
		if (
			moment(newStartDate).day() === getNumberForFullCalendarWeekday(recurringEvent.included[0].attributes.wkst)
		) {
			start = newStartDate;
			end = newEndDate;
			break;
		}
	}

	// loop over all new weekdays from startDate to untilDate
	for (let i = 0; start + i * oneWeekIndicator <= until; i += 1) {
		const newStartDate = start + i * oneWeekIndicator;
		const newEndDate = end + i * oneWeekIndicator;

		recurringEvents.push({
			title: recurringEvent.summary,
			summary: recurringEvent.summary,
			location: recurringEvent.location,
			description: recurringEvent.description,
			url: recurringEvent.url,
			color: recurringEvent.color,
			start: newStartDate,
			end: newEndDate,
		});
	}

	return recurringEvents;
};

/**
 * handle recurring events for calendar
 * @param event {Event} - a event which could contain a recurring value
 * @returns events [] - new set of events
 */
const mapRecurringEvent = (event) => {
	if (event.included && event.included[0].attributes.freq === 'WEEKLY') {
		return createRecurringEvents(event);
	}

	return [event];
};

/**
 * maps properties of a event to fit calendar, e.g. url and color
 * If any error is accoured then return course or team with default color.
 * @param event
 */
const mapEventProps = (event, req) => {
	if (event['x-sc-courseId']) {
		return api(req).get(`/courses/${event['x-sc-courseId']}`).then((course) => {
			event.url = event['x-sc-courseTimeId'] ? `/courses/${course._id}` : '';
			event.color = course.color;
			return event;
		}).catch((err) => {
			// eslint-disable-next-line no-console
			console.log("event['x-sc-courseId']", err);
			event.url = '';
			event.color = '#ff0000';
			return event;
		});
	}

	if (event['x-sc-teamId']) {
		return api(req).get(`/teams/${event['x-sc-teamId']}`).then((team) => {
			event.url = '';
			event.color = team.color;
			return event;
		}).catch((err) => {
			// eslint-disable-next-line no-console
			console.log("event['x-sc-teamId']", err);
			event.url = '';
			event.color = '#ff0000';
			return event;
		});
	}

	return event;
};

/**
 * retrieves the next date for given weekly courseTimes
 * @param courseTimes - the times of a course
 * @return {String} - a formatted date string
 */
const getNextEventForCourseTimes = (courseTimes) => {
	if ((courseTimes || []).length <= 0) return;
	const nextDates = _.map(courseTimes, (ct) => {
		let weekDayIdentifier = ct.weekday + 1; // moment starts on sunday

		// if current week's weekday is over, take the one next week
		if (moment().day() > weekDayIdentifier) weekDayIdentifier += 7;

		// return nothing if date has already passed
		const date = moment().day(weekDayIdentifier).hours(0).minutes(0)
			.seconds(0)
			.milliseconds(ct.startTime);
		if (date.isBefore()) return;

		// has to store index, because .indexOf with moment arrays does not work
		// eslint-disable-next-line consistent-return
		return date;
	});

	// find nearest day from now
	const minDate = _.min(nextDates);
	// eslint-disable-next-line consistent-return
	return moment(minDate).format('DD.MM.YYYY HH:mm');
};

if (!Date.prototype.toLocalISOString) {
	(function assignDateFunction() {
		function pad(number) {
			if (number < 10) {
				return `0${number}`;
			}
			return number;
		}

		// eslint-disable-next-line no-extend-native
		Date.prototype.toLocalISOString = () => `${this.getFullYear()
		}-${pad(this.getMonth() + 1)
		}-${pad(this.getDate())
		}T${pad(this.getHours())
		}:${pad(this.getMinutes())
		}:${pad(this.getSeconds())
		}.${(this.getMilliseconds() / 1000).toFixed(3).slice(2, 5)
		}Z`;
	}());
}

module.exports = {
	getIsoWeekdayForNumber,
	getWeekdayForNumber,
	getNumberForWeekday,
	getNumberForFullCalendarWeekday,
	createRecurringEvents,
	mapRecurringEvent,
	mapEventProps,
	getNextEventForCourseTimes,
};
<|endoftext|>


<commit_before>/**
 * Tests for string/sprintf
 * @author Rob Taylor [manix84@gmail.com]
 * @requires string/sprintf
 */
define([
    'string/sprintf'
], function (sprintf) {
    module('string/sprintf');

    test('sprintf', function () {
        equal(sprintf("Integer: %d, String: %s, Not A Float: \\%f, Float: %f", ["String", 1.2, 3]), "Integer: 3, String: String Not A Float: \\%f, Float: 1.2", "SprintF Has Replaced The Special Characters");
    });
});
<commit_msg>Fixing test.<commit_after>/**
 * Tests for string/sprintf
 * @author Rob Taylor [manix84@gmail.com]
 * @requires string/sprintf
 */
define([
    'string/sprintf'
], function (sprintf) {
    module('string/sprintf');

    test('sprintf', function () {
        equal(
            sprintf("Integer: %d, String: %s, Not A Float: \\%f, Float: %f", ["String", 1.2, 3]),
            "Integer: 3, String: String, Not A Float: \\%f, Float: 1.2",
            "SprintF Has Replaced The Special Characters"
        );
    });
});
<|endoftext|>


<commit_before>
$(document).ready(function(){

var queryURL = "https://opentdb.com/api.php?amount=1";
var correct_count=0;
var incorrect_count=0;
var time_left;
var question_number_count =1;
var time_interval;
var correct_answer;

$("#start_btn").on("click",function(){
	generate_question();
	timer();
});

function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

function generate_question(){

	$(".opening_screen").css("display","none");

	$.ajax({
	url:queryURL,
	method: 'GET'
	}).done(function(response){

	var incorrect_answers=response.results[0].incorrect_answers
	var question_text;
	var answers_array=[];

	question_text = response.results[0].question;
	answers_array[0]=response.results[0].correct_answer;
	correct_answer=response.results[0].correct_answer;

	for (var i=1; i<=incorrect_answers.length;i++){

		answers_array[i]=incorrect_answers[(i-1)];
	}

	shuffleArray(answers_array);
	var answer_button_count='';
	console.log(answers_array)
	for (var j=0;j<answers_array.length;j++){
		answer_button_count = answer_button_count+'<button class="answer_buttons">'+answers_array[j]+'</button>
';
	}

	var question_screen_form = '

Question #'+question_number_count+'

'+question_text+'

'+answer_button_count+'

';

	$(".container").append(question_screen_form);

	})
};

$(document).on("click",".answer_buttons",function(){
	question_number_count +=1;

	if ($(this).text()==correct_answer){
		correct_count +=1;
	}
	else{
		incorrect_count+=1;
	}
	score_display();
	clear();

})

function timer(){
	time_left=30;
	time_interval = setInterval(time_decrease, 1000);
	setTimeout(timeUp, 1000 * (time_left));

	function time_decrease (){
		time_left -=1;
		console.log(time_left);
		$(".timer").children(".timer_text").text(time_left);
	}

}

function timeUp(){
	clearInterval(time_interval);

	$(".question_screen").remove();
	$(".opening_screen").children("#opening_text").text("Game Over");
	$(".opening_screen").children("#opening_text").css("left","290px");
	$(".opening_screen").children("#start_btn").text("Restart");
	$(".opening_screen").css("display","block");

	}

function clear(){
	$("#prev_ans").text("Correct answer was:   "+correct_answer);
	$(".question_screen").remove();
	generate_question()

}

function score_display(){
	$(".score_div").html('Correct Answer:'+correct_count+'

Incorrect Answer: '+incorrect_count+'')
}

});<commit_msg>timer bug fixed<commit_after>
$(document).ready(function(){

var queryURL = "https://opentdb.com/api.php?amount=1";
var correct_count=0;
var incorrect_count=0;
var time_left;
var question_number_count =1;
var time_interval;
var correct_answer;
var time_up;

$("#start_btn").on("click",function(){
	generate_question();
	timer();
});

function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

function generate_question(){

	$(".opening_screen").css("display","none");

	$.ajax({
	url:queryURL,
	method: 'GET'
	}).done(function(response){

	var incorrect_answers=response.results[0].incorrect_answers
	var question_text;
	var answers_array=[];

	question_text = response.results[0].question;
	answers_array[0]=response.results[0].correct_answer;
	correct_answer=response.results[0].correct_answer;

	for (var i=1; i<=incorrect_answers.length;i++){

		answers_array[i]=incorrect_answers[(i-1)];
	}

	shuffleArray(answers_array);
	var answer_button_count='';
	console.log(answers_array)
	for (var j=0;j<answers_array.length;j++){
		answer_button_count = answer_button_count+'<button class="answer_buttons">'+answers_array[j]+'</button>
';
	}

	var question_screen_form = '

Question #'+question_number_count+'

'+question_text+'

'+answer_button_count+'

';

	$(".container").append(question_screen_form);

	})
};

$(document).on("click",".answer_buttons",function(){
	question_number_count +=1;

	if ($(this).text()==correct_answer){
		correct_count +=1;
	}
	else{
		incorrect_count+=1;
	}
	score_display();
	clear();

})

function timer(){
	time_left=5;
	time_interval = setInterval(time_decrease, 1000);
	time_up = setTimeout(timeUp, 1000 * 5);

	function time_decrease (){
		time_left -=1;
		console.log(time_left);
		$(".timer").children(".timer_text").text(time_left);
	}

}

function timeUp(){
	clearInterval(time_interval);

	$(".question_screen").remove();
	$(".opening_screen").children("#opening_text").text("Game Over");
	$(".opening_screen").children("#opening_text").css("left","290px");
	$(".opening_screen").children("#start_btn").text("Restart");
	$(".opening_screen").css("display","block");

	}

function clear(){
	$("#prev_ans").text("Correct answer was:   "+correct_answer);
	$(".question_screen").remove();
	generate_question()
	clearInterval(time_interval);
	clearTimeout(time_up);
	timer();

}

function score_display(){
	$(".score_div").html('Correct Answer:'+correct_count+'

Incorrect Answer: '+incorrect_count+'')
}

});<|endoftext|>


<commit_before>import _ from "lodash";
import objectPath from "object-path"
import { ServiceManager } from "../index"
import { parameterizedConfiguration } from "../../../utils/configurations";

import config from '../../../config';
import { events } from '../../../lib/vis-graphs/utils/types';

export const ActionTypes = {
    SERVICE_MANAGER_DID_START_REQUEST: "SERVICE_MANAGER_DID_START_REQUEST",
    SERVICE_MANAGER_DID_RECEIVE_RESPONSE: "SERVICE_MANAGER_DID_RECEIVE_RESPONSE",
    SERVICE_MANAGER_DID_RECEIVE_ERROR: "SERVICE_MANAGER_DID_RECEIVE_ERROR",
    SERVICE_MANAGER_DELETE_REQUEST: "SERVICE_MANAGER_DELETE_REQUEST",
    SERVICE_MANAGER_SCROLL_DATA: "SERVICE_MANAGER_SCROLL_DATA",
    SERVICE_MANAGER_RESET_SERVICES: "SERVICE_MANAGER_RESET_SERVICES"
};

export const ActionKeyStore = {
    ERROR: "error",
    IS_FETCHING: "isFetching",
    RESULTS: "results",
    REQUESTS: "requests",
    EXPIRATION_DATE: "expirationDate",
    SCROLL_DATA: 'scrollData',
    DASHBOARD: 'dashboard'
};

// TODO: Temporary - Replace this part in the middleware
function executeScript(scriptName, context, dashboard = null) {

    const requestID = ServiceManager.getRequestID(scriptName, context);

    return (dispatch, getState) => {
        dispatch(didStartRequest(requestID, dashboard));

        return ServiceManager.executeScript(scriptName, context)
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });
    }
}

function isPagingEvent(scrollData) {
    return objectPath.has(scrollData, 'event') && scrollData.event === events.PAGING;
}

function isScrollValid(scrollData) {
    return objectPath.has(scrollData, 'expiration') && Date.now() < scrollData.expiration;
}

function getScrollStatus({
    scrollData,
    total,
    pageSize
}) {
    // Check whether Data is not expired
    const isValidData = isPagingEvent(scrollData) && isScrollValid(scrollData);
    const currentPage = objectPath.get(scrollData, 'page') || 1;
    if(!isValidData)
        return 'INVALID';

    if(total >= ((currentPage - 1) * pageSize + 1)) {
        return 'EXISTS';
    }

    return 'NOT_EXISTS'
}

async function getDataFromStartToCurrentPage({
    data,
    query,
    results,
    startPage,
    currentPage,
    state
}) {
    let service = ServiceManager.getService(query.service);
    let records = [...data];

    let nextQuery = results.nextQuery;

    while(nextQuery && startPage <= currentPage) {
        let result =   await service.fetch(nextQuery, state, records.length)
        let response = ServiceManager.tabify(query, result.response)

        if (response && response.length)
            records = [...records, ...response];

        nextQuery = result.nextQuery;
        startPage++;
    }

    return {
        data,
        nextQuery
    }
}

/*
    Make a query on the service based on the service name.

    Arguments:
    * query: the query configuration
    * context: the context if the query should be parameterized
    * forceCache: a boolean to force storing the value for a long period
*/
function fetch(query, context, forceCache, scroll = false, dashboard = null) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        const scrollData = getState().services.getIn([ActionKeyStore.SCROLL_DATA, query.vizID]) || {};

        let data = [],
            currentPage = objectPath.get(scrollData, 'page') || 1,
            startPage = currentPage,
            updatedQuery = { ...query, scroll },
            scrollId = null,
            pageSize = objectPath.get(updatedQuery, service.getSizePath());

        if(scroll) {
            if (!pageSize) {
                // Set the size for VSD / ES query for pagination purpose.
                updatedQuery = service.updateSize(updatedQuery, config.DATA_PER_PAGE_LIMIT);
            }

            data = getState().services.getIn([ActionKeyStore.REQUESTS, requestID, ActionKeyStore.RESULTS]) || [];

            const status = getScrollStatus({
                scrollData,
                total: data.length,
                pageSize
            });

            switch (status) {
                case 'INVALID':
                    // Reset data and start from first page
                    data = [];
                    startPage = 1;
                    break;

                case 'NOT_EXISTS':
                    // Fetch next page
                    scrollId = scrollData.scroll_id
                    break;

                case 'EXISTS':
                    // Data already Preset no need to do request
                    dispatch(updateScroll(query.vizID, {
                        event: null,
                        page: currentPage
                    }));

                    return Promise.resolve();
            }
        }

        // If Page number is not equal to 1 then we must use Scroll Base Query else use normal Query
        updatedQuery = startPage !== 1 ? service.getScrollQuery(updatedQuery, scrollId) : updatedQuery;
        dispatch(didStartRequest(requestID, dashboard));

        return service.fetch(updatedQuery, getState())
            .then(
                async (results) => {
                    // merging "data" here for the case of paging, otherwise will be []
                    data = [...data, ...ServiceManager.tabify(query, results.response)];

                    if(scroll) {
                        startPage++;

                        // Will be valid in case of scroll get expired
                        const response = await getDataFromStartToCurrentPage({
                            data,
                            query,
                            results,
                            startPage,
                            currentPage,
                            state: getState()
                        })

                        data = response.data;

                        dispatch(updateScroll(
                            query.vizID,
                            {
                                scroll_id: objectPath.get(response.nextQuery, 'query.scroll_id'),
                                expiration: Date.now() + config.SCROLL_CACHING_QUERY_TIME,
                                event: null,
                                size: objectPath.get(response.nextQuery, 'length'),
                                pageSize,
                            }
                        ))
                    }

                    dispatch(didReceiveResponse(requestID, data, false))

                    return Promise.resolve(data);
            },
            (error) => {
                if (process.env.NODE_ENV === "development" && service.hasOwnProperty("getMockResponse")) {
                    try {
                        const response = service.getMockResponse(query);
                        dispatch(didReceiveResponse(requestID, response, forceCache));
                    } catch(e) {
                        dispatch(didReceiveError(requestID, e));
                    }

                    return Promise.resolve();
                }
                else
                {
                    dispatch(didReceiveError(requestID, error));
                    return Promise.resolve();
                }
            });

    }
}

function shouldFetch(request) {
    if (!request)
        return true;

    let currentDate = Date.now(),
        expireDate  = request.get(ActionKeyStore.EXPIRATION_DATE);

    return !request.get(ActionKeyStore.IS_FETCHING) && currentDate > expireDate;
}

function fetchIfNeeded(query, context, forceCache, scroll, dashboard = null) {

    // TODO: Temporary - Replace this part in the middleware
    const isScript = typeof(query) === "string";
    let requestID;

    if (isScript)
        requestID = ServiceManager.getRequestID(query, context);
    else {
        let service = ServiceManager.getService(query.service);
        requestID = service.getRequestID(query, context);
    }

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        let mustFetch = false;

        if(scroll) {
            const scrollData = state.services.getIn([ActionKeyStore.SCROLL_DATA, query.vizID]);
            mustFetch = scrollData && scrollData.event || false;
        }

        if (shouldFetch(request) || mustFetch) {
            if (isScript)
                return dispatch(executeScript(query, context, dashboard));
            else
                return dispatch(fetch(query, context, forceCache, scroll, dashboard));

        } else {
            return Promise.resolve();
        }
    }
}

function post(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));

        return service.post(query, body, getState())
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });

    }
}

function postIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(post(query, body, context, forceCache));

        } else {
            return Promise.resolve();
        }
    }
}

function update(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));

        return service.update(query, body, getState())
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });
    }
}

function updateIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(update(query, body, context, forceCache));

        } else {
            return Promise.resolve();
        }
    }
}

function add(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));
        return service.add(query, body, getState())
            .then(
                (results) => {
                    dispatch(didReceiveResponse(requestID, results));
                    return Promise.resolve(results);
                },
                (error) => {
                    dispatch(didReceiveError(requestID, error));
                    return Promise.resolve();
                });
    }
}

function addIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
            request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(add(query, body, context, forceCache));
        } else {
            return Promise.resolve();
        }
    }
}

function didStartRequest(requestID, dashboard = null) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_START_REQUEST,
        requestID: requestID,
        dashboard
    };
}

function didReceiveResponse(requestID, results, forceCache = false) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_RECEIVE_RESPONSE,
        requestID,
        results,
        forceCache
    };
}

function didReceiveError(requestID, error) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_RECEIVE_ERROR,
        requestID: requestID,
        error: error
    };
}

function deleteRequest(requestID) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DELETE_REQUEST,
        requestID: requestID,
    };
}

function updateScroll(id, data) {
    return {
        type: ActionTypes.SERVICE_MANAGER_SCROLL_DATA,
        id,
        data,
    };
}

export const Actions = {
    fetch: fetch,
    fetchIfNeeded: fetchIfNeeded,
    didStartRequest: didStartRequest,
    didReceiveResponse: didReceiveResponse,
    didReceiveError: didReceiveError,
    postIfNeeded: postIfNeeded,
    deleteRequest: deleteRequest,
    updateIfNeeded: updateIfNeeded,
    addIfNeeded: addIfNeeded,
    updateScroll: updateScroll,
};
<commit_msg>[feature]: add refresh option on scroll table<commit_after>import _ from "lodash";
import objectPath from "object-path"
import { ServiceManager } from "../index"
import { parameterizedConfiguration } from "../../../utils/configurations";

import config from '../../../config';
import { events } from '../../../lib/vis-graphs/utils/types';

export const ActionTypes = {
    SERVICE_MANAGER_DID_START_REQUEST: "SERVICE_MANAGER_DID_START_REQUEST",
    SERVICE_MANAGER_DID_RECEIVE_RESPONSE: "SERVICE_MANAGER_DID_RECEIVE_RESPONSE",
    SERVICE_MANAGER_DID_RECEIVE_ERROR: "SERVICE_MANAGER_DID_RECEIVE_ERROR",
    SERVICE_MANAGER_DELETE_REQUEST: "SERVICE_MANAGER_DELETE_REQUEST",
    SERVICE_MANAGER_SCROLL_DATA: "SERVICE_MANAGER_SCROLL_DATA",
    SERVICE_MANAGER_RESET_SERVICES: "SERVICE_MANAGER_RESET_SERVICES"
};

export const ActionKeyStore = {
    ERROR: "error",
    IS_FETCHING: "isFetching",
    RESULTS: "results",
    REQUESTS: "requests",
    EXPIRATION_DATE: "expirationDate",
    SCROLL_DATA: 'scrollData',
    DASHBOARD: 'dashboard'
};

// TODO: Temporary - Replace this part in the middleware
function executeScript(scriptName, context, dashboard = null) {

    const requestID = ServiceManager.getRequestID(scriptName, context);

    return (dispatch, getState) => {
        dispatch(didStartRequest(requestID, dashboard));

        return ServiceManager.executeScript(scriptName, context)
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });
    }
}

function isPagingEvent(scrollData) {
    return objectPath.has(scrollData, 'event') && scrollData.event === events.PAGING;
}

function isScrollValid(scrollData) {
    return objectPath.has(scrollData, 'expiration') && Date.now() < scrollData.expiration;
}

function isRefreshEvent(scrollData) {
    return objectPath.has(scrollData, 'event') && scrollData.event === events.REFRESH;
}

function getScrollStatus({
    scrollData,
    total,
    pageSize
}) {
    // Check whether Data is not expired
    const isValidData = isPagingEvent(scrollData) && isScrollValid(scrollData);
    const currentPage = objectPath.get(scrollData, 'page') || 1;

    if(!isValidData || isRefreshEvent())
        return 'INVALID';

    if(total >= ((currentPage - 1) * pageSize + 1)) {
        return 'EXISTS';
    }

    return 'NOT_EXISTS'
}

async function getDataFromStartToCurrentPage({
    data,
    query,
    results,
    startPage,
    currentPage,
    state
}) {
    let service = ServiceManager.getService(query.service);
    let records = [...data];

    let nextQuery = results.nextQuery;

    while(nextQuery && startPage <= currentPage) {
        let result =   await service.fetch(nextQuery, state, records.length)
        let response = ServiceManager.tabify(query, result.response)

        if (response && response.length)
            records = [...records, ...response];

        nextQuery = result.nextQuery;
        startPage++;
    }

    return {
        data,
        nextQuery
    }
}

/*
    Make a query on the service based on the service name.

    Arguments:
    * query: the query configuration
    * context: the context if the query should be parameterized
    * forceCache: a boolean to force storing the value for a long period
*/
function fetch(query, context, forceCache, scroll = false, dashboard = null) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        const scrollData = getState().services.getIn([ActionKeyStore.SCROLL_DATA, query.vizID]) || {};

        let data = [],
            currentPage = objectPath.get(scrollData, 'page') || 1,
            startPage = currentPage,
            updatedQuery = { ...query, scroll },
            scrollId = null,
            pageSize = objectPath.get(updatedQuery, service.getSizePath());

        if(scroll) {
            if (!pageSize) {
                // Set the size for VSD / ES query for pagination purpose.
                updatedQuery = service.updateSize(updatedQuery, config.DATA_PER_PAGE_LIMIT);
            }

            data = getState().services.getIn([ActionKeyStore.REQUESTS, requestID, ActionKeyStore.RESULTS]) || [];

            const status = getScrollStatus({
                scrollData,
                total: data.length,
                pageSize
            });

            switch (status) {
                case 'INVALID':
                    // Reset data and start from first page
                    data = [];
                    startPage = 1;
                    break;

                case 'NOT_EXISTS':
                    // Fetch next page
                    scrollId = scrollData.scroll_id
                    break;

                case 'EXISTS':
                    // Data already Preset no need to do request
                    dispatch(updateScroll(query.vizID, {
                        event: null,
                        page: currentPage
                    }));

                    return Promise.resolve();
            }
        }

        // If Page number is not equal to 1 then we must use Scroll Base Query else use normal Query
        updatedQuery = startPage !== 1 ? service.getScrollQuery(updatedQuery, scrollId) : updatedQuery;
        dispatch(didStartRequest(requestID, dashboard));

        return service.fetch(updatedQuery, getState())
            .then(
                async (results) => {
                    // merging "data" here for the case of paging, otherwise will be []
                    data = [...data, ...ServiceManager.tabify(query, results.response)];

                    if(scroll) {
                        startPage++;

                        // Will be valid in case of scroll get expired
                        const response = await getDataFromStartToCurrentPage({
                            data,
                            query,
                            results,
                            startPage,
                            currentPage,
                            state: getState()
                        })

                        data = response.data;

                        dispatch(updateScroll(
                            query.vizID,
                            {
                                scroll_id: objectPath.get(response.nextQuery, 'query.scroll_id'),
                                expiration: Date.now() + config.SCROLL_CACHING_QUERY_TIME,
                                event: null,
                                size: objectPath.get(response.nextQuery, 'length'),
                                pageSize,
                            }
                        ))
                    }

                    dispatch(didReceiveResponse(requestID, data, false))

                    return Promise.resolve(data);
            },
            (error) => {
                if (process.env.NODE_ENV === "development" && service.hasOwnProperty("getMockResponse")) {
                    try {
                        const response = service.getMockResponse(query);
                        dispatch(didReceiveResponse(requestID, response, forceCache));
                    } catch(e) {
                        dispatch(didReceiveError(requestID, e));
                    }

                    return Promise.resolve();
                }
                else
                {
                    dispatch(didReceiveError(requestID, error));
                    return Promise.resolve();
                }
            });

    }
}

function shouldFetch(request) {
    if (!request)
        return true;

    let currentDate = Date.now(),
        expireDate  = request.get(ActionKeyStore.EXPIRATION_DATE);

    return !request.get(ActionKeyStore.IS_FETCHING) && currentDate > expireDate;
}

function fetchIfNeeded(query, context, forceCache, scroll, dashboard = null) {

    // TODO: Temporary - Replace this part in the middleware
    const isScript = typeof(query) === "string";
    let requestID;

    if (isScript)
        requestID = ServiceManager.getRequestID(query, context);
    else {
        let service = ServiceManager.getService(query.service);
        requestID = service.getRequestID(query, context);
    }

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        let mustFetch = false;

        if(scroll) {
            const scrollData = state.services.getIn([ActionKeyStore.SCROLL_DATA, query.vizID]);
            mustFetch = scrollData && scrollData.event || false;
        }

        if (shouldFetch(request) || mustFetch) {
            if (isScript)
                return dispatch(executeScript(query, context, dashboard));
            else
                return dispatch(fetch(query, context, forceCache, scroll, dashboard));

        } else {
            return Promise.resolve();
        }
    }
}

function post(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));

        return service.post(query, body, getState())
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });

    }
}

function postIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(post(query, body, context, forceCache));

        } else {
            return Promise.resolve();
        }
    }
}

function update(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));

        return service.update(query, body, getState())
            .then(
            (results) => {
                dispatch(didReceiveResponse(requestID, results));
                return Promise.resolve(results);
            },
            (error) => {
                dispatch(didReceiveError(requestID, error));
                return Promise.resolve();
            });
    }
}

function updateIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
              request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(update(query, body, context, forceCache));

        } else {
            return Promise.resolve();
        }
    }
}

function add(query, body, context, forceCache) {
    let service = ServiceManager.getService(query.service);

    return (dispatch, getState) => {
        let requestID = service.getRequestID(query, context);

        if (context) {
            const pQuery = parameterizedConfiguration(query, context);

            if (pQuery)
                query = pQuery;
            else
                return Promise.reject("Provided context does not allow to parameterized query " + query.id);
        }

        dispatch(didStartRequest(requestID));
        return service.add(query, body, getState())
            .then(
                (results) => {
                    dispatch(didReceiveResponse(requestID, results));
                    return Promise.resolve(results);
                },
                (error) => {
                    dispatch(didReceiveError(requestID, error));
                    return Promise.resolve();
                });
    }
}

function addIfNeeded(query, body, context, forceCache) {
    const service = ServiceManager.getService(query.service);
    const requestID = service.getRequestID(query, context);

    return (dispatch, getState) => {
        if (!requestID)
            return Promise.reject();

        const state = getState(),
            request = state.services.getIn([ActionKeyStore.REQUESTS, requestID]);

        if (shouldFetch(request)) {
            return dispatch(add(query, body, context, forceCache));
        } else {
            return Promise.resolve();
        }
    }
}

function didStartRequest(requestID, dashboard = null) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_START_REQUEST,
        requestID: requestID,
        dashboard
    };
}

function didReceiveResponse(requestID, results, forceCache = false) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_RECEIVE_RESPONSE,
        requestID,
        results,
        forceCache
    };
}

function didReceiveError(requestID, error) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DID_RECEIVE_ERROR,
        requestID: requestID,
        error: error
    };
}

function deleteRequest(requestID) {
    return {
        type: ActionTypes.SERVICE_MANAGER_DELETE_REQUEST,
        requestID: requestID,
    };
}

function updateScroll(id, data) {
    return {
        type: ActionTypes.SERVICE_MANAGER_SCROLL_DATA,
        id,
        data,
    };
}

export const Actions = {
    fetch: fetch,
    fetchIfNeeded: fetchIfNeeded,
    didStartRequest: didStartRequest,
    didReceiveResponse: didReceiveResponse,
    didReceiveError: didReceiveError,
    postIfNeeded: postIfNeeded,
    deleteRequest: deleteRequest,
    updateIfNeeded: updateIfNeeded,
    addIfNeeded: addIfNeeded,
    updateScroll: updateScroll,
};
<|endoftext|>


<commit_before>
/*
  jGet JavaScript library v 0.1

  Copyright Mayank Srivastav

  Date: 27-June-2017
*/

(function (window) {
  "use strict";
  // Global shorthands
  let _arr = [],
    _keys = Object.keys,
    _values = Object.values,
    _splice = _arr.splice,
    _proto = Object.prototype,
    _filter = _arr.filter,
    _map = _arr.map,
    _document = window.document;

  // jGet local copy
  // TODO: pass context argument
  let jGet = function(selector) {
    return new jGet.py.init(selector);
  };

  jGet.py = jGet.prototype = {
    constructor: jGet,

    map: function(elem, callback) {
      return jGet.map(elem, callback);
    }
  };

  // extends the source object with
  // destination object

  // TODO: Handle single arg
  jGet.extend = function() {
    let source, dest, args, len;
    let i;

    // do nothing if source is not
    // specified
    if (arguments.length === 0) {
      return;
    }

    i = len = arguments.length;

    source = arguments[0];
    // dest = arguments[1];

    // TODO: extend the jGet object
    if (len === 1) {
    } else {
      i = 1;
    }
     // for every object in args
    for (; i < len; ++i) {
      dest = arguments[i];
      // if dest is undefined or null
      // or not an object, then move
      // ahead
      if (dest && jGet.isObject(dest)) {
        // TODO: Use for...in for cross
        // browser compatibility
        const _keys = Object.keys(dest);
        // handle empty object case
        if (_keys.length < 1) {
          continue;
        }

        // for every key, assign it to the target
        // object
        for (let i = 0; i < _keys.length; ++i) {
          source[_keys[i]] = dest[_keys[i]];
        }
      }
    }

    return source;
  };

  // check if the arg is an
  // object. It could be a
  // function object also
  jGet.isObject = function(obj) {
    return (typeof obj === "object" || typeof obj === "function") && !!obj;
  };

  // check if object is an
  // array
  jGet.isArray = function(obj) {
    // object is null or undefined
    if (!obj) {
      return false;
    }

    return Object.prototype.toString.call(obj) === "[object Array]";
  };

})(window);
<commit_msg>Added code for isArrayLike method<commit_after>
/*
  jGet JavaScript library v 0.1

  Copyright Mayank Srivastav

  Date: 27-June-2017
*/

(function (window) {
  "use strict";
  // Global shorthands
  let _arr = [],
    _keys = Object.keys,
    _values = Object.values,
    _splice = _arr.splice,
    _proto = Object.prototype,
    _filter = _arr.filter,
    _map = _arr.map,
    _document = window.document;

  // jGet local copy
  // TODO: pass context argument
  let jGet = function(selector) {
    return new jGet.py.init(selector);
  };

  jGet.py = jGet.prototype = {
    constructor: jGet,

    map: function(elem, callback) {
      return jGet.map(elem, callback);
    }
  };

  // extends the source object with
  // destination object

  // TODO: Handle single arg
  jGet.extend = function() {
    let source, dest, args, len;
    let i;

    // do nothing if source is not
    // specified
    if (arguments.length === 0) {
      return;
    }

    i = len = arguments.length;

    source = arguments[0];
    // dest = arguments[1];

    // TODO: extend the jGet object
    if (len === 1) {
    } else {
      i = 1;
    }
     // for every object in args
    for (; i < len; ++i) {
      dest = arguments[i];
      // if dest is undefined or null
      // or not an object, then move
      // ahead
      if (dest && jGet.isObject(dest)) {
        // TODO: Use for...in for cross
        // browser compatibility
        const _keys = Object.keys(dest);
        // handle empty object case
        if (_keys.length < 1) {
          continue;
        }

        // for every key, assign it to the target
        // object
        for (let i = 0; i < _keys.length; ++i) {
          source[_keys[i]] = dest[_keys[i]];
        }
      }
    }

    return source;
  };

  // check if the arg is an
  // object. It could be a
  // function object also
  jGet.isObject = function(obj) {
    return (typeof obj === "object" || typeof obj === "function") && !!obj;
  };

  // check if object is an
  // array
  jGet.isArray = function(obj) {
    // object is null or undefined
    if (!obj) {
      return false;
    }

    return Object.prototype.toString.call(obj) === "[object Array]";
  };

  // check if the object is an Array
  // like structure, i.e having length
  // property

  // TODO: refactor; not the best code
  jGet.isArrayLike = function(obj) {
    if (
      obj === null ||
      obj === undefined ||
      typeof obj === "boolean" ||
      typeof obj === "number"
    ) {
      return false;
    }

    return "length" in obj;
  };

})(window);
<|endoftext|>


<commit_before>var time = {
  day: 480,
  completed: 0,
  lowest: 480,
  remaining: 480
};
var container = $('.container');
var focus = $('

');
var completed = $('.completed');
function focusTitle() {
  $path = window.location.pathname;
  if ($path.indexOf('focus') !== -1) {
    $list = $('.task-list input[type="checkbox"]');
    $newTitle = true;
    $i = 0;
    while ($newTitle) {
      if (!$($list[$i]).is(':checked')) {
        $text = $($list[$i]).parent().text().trim();
        $newTitle = false;
      }
      $i++;
    }
    $('title').text($text + "| myApp");
  }
}
function drawTaskSize() {
  $('#focus li').css('height', ((1 - ($('#completed').height() / $(window).height())) * 100 / $('#focus li').length + 'vh'));
  $('#completed li').css('height', 'auto');
}
function drawFocusTasks() {
  completed = $('.completed');
  $('#completed').append(completed);
  $('li:not(.completed)').prependTo('#tasks');

  time.completed = 0;
  completed.each(function () {
    time.completed += ($(this).data("time")) ? $(this).data("time") : 0;
  });

  time.remaining = time.day - time.completed;
  while (time.remaining > 0) {
    task = $('#tasks li:first');
    if (task.length) {
      time.remaining -= (task.data("time")) ? task.data("time") : 0;
      focus.append(task);
    } else {
      break;
    }
  }
  focusTitle();
  focusTaskSize();
}
function updateOrder() {
  var dataString = "";
  $('.task-list li').each(function () {
    dataString += "tasks[][id]=" + $(this).data('id') + "&";
  });
  $.ajax({
    data: dataString,
    dataType: "json",
    type: 'POST',
    url: tasks_order
  }).done(drawFocusTasks());
}
function focusTaskChange() {
  $li = $(this).parent().parent();
  $ul = $li.parent();
  $ajaxValue = ($(this).is(":checked")) ? 1 : 0;
  $.ajax({
    type: "POST",
    url: tasks_path + $(this).data('taskid') + "/edit",
    dataType: "json",
    data: {
      "completed": $ajaxValue
    }
  }).done(function () {
    if ($ajaxValue) {
      $($li).addClass('completed');
    } else {
      $($li).removeClass('completed');
    }
    drawFocusTasks();
  });
}
function focusInit() {
  focus.prependTo(container);
  // $('[data-toggle="tooltip"]').tooltip();
  $('[data-toggle="popover"]').popover({html: true});
  // Checking Tasks
  $('.task-list input[type="checkbox"]').change(focusTaskChange);
  // Disabling on mobile devices
  // Maybe I should use screen width
  if (!touch) {
    $("#focus, #tasks").sortable({
      connectWith: ".task-list",
      items: "li:not(.completed)",
      update: updateOrder
    });
  }
  drawFocusTasks();
}
<commit_msg>bug in tasks.js|<commit_after>var time = {
  day: 480,
  completed: 0,
  lowest: 480,
  remaining: 480
};
var container = $('.container');
var focus = $('

');
var completed = $('.completed');
function focusTitle() {
  $path = window.location.pathname;
  if ($path.indexOf('focus') !== -1) {
    $list = $('.task-list input[type="checkbox"]');
    $newTitle = true;
    $i = 0;
    while ($newTitle) {
      if (!$($list[$i]).is(':checked')) {
        $text = $($list[$i]).parent().text().trim();
        $newTitle = false;
      }
      $i++;
    }
    $('title').text($text + "| myApp");
  }
}
function drawTaskSize() {
  $('#focus li').css('height', ((1 - ($('#completed').height() / $(window).height())) * 100 / $('#focus li').length + 'vh'));
  $('#completed li').css('height', 'auto');
}
function drawFocusTasks() {
  completed = $('.completed');
  $('#completed').append(completed);
  $('li:not(.completed)').prependTo('#tasks');

  time.completed = 0;
  completed.each(function () {
    time.completed += ($(this).data("time")) ? $(this).data("time") : 0;
  });

  time.remaining = time.day - time.completed;
  while (time.remaining > 0) {
    task = $('#tasks li:first');
    if (task.length) {
      time.remaining -= (task.data("time")) ? task.data("time") : 0;
      focus.append(task);
    } else {
      break;
    }
  }
  focusTitle();
  drawTaskSize();
}
function updateOrder() {
  var dataString = "";
  $('.task-list li').each(function () {
    dataString += "tasks[][id]=" + $(this).data('id') + "&";
  });
  $.ajax({
    data: dataString,
    dataType: "json",
    type: 'POST',
    url: tasks_order
  }).done(drawFocusTasks());
}
function focusTaskChange() {
  $li = $(this).parent().parent();
  $ul = $li.parent();
  $ajaxValue = ($(this).is(":checked")) ? 1 : 0;
  $.ajax({
    type: "POST",
    url: tasks_path + $(this).data('taskid') + "/edit",
    dataType: "json",
    data: {
      "completed": $ajaxValue
    }
  }).done(function () {
    if ($ajaxValue) {
      $($li).addClass('completed');
    } else {
      $($li).removeClass('completed');
    }
    drawFocusTasks();
  });
}
function focusInit() {
  focus.prependTo(container);
  // $('[data-toggle="tooltip"]').tooltip();
  $('[data-toggle="popover"]').popover({html: true});
  // Checking Tasks
  $('.task-list input[type="checkbox"]').change(focusTaskChange);
  // Disabling on mobile devices
  // Maybe I should use screen width
  if (!touch) {
    $("#focus, #tasks").sortable({
      connectWith: ".task-list",
      items: "li:not(.completed)",
      update: updateOrder
    });
  }
  drawFocusTasks();
}
<|endoftext|>