persistanz
Version:
Object relational mapping (ORM) library with unique features.
604 lines (508 loc) • 26.2 kB
JavaScript
;
var prepare = require("./attic/prepare.js");
var conf = prepare.loadConfig();
var Persistanz = require("../lib/Persistanz.js");
var assert = require("chai").assert;
require('co-mocha');
describe("Basic CRUD without a configuration", function(done) {
for (var adapterName of conf.applyTestsTo) {
describe("running for " + adapterName, function() {
var pers;
(function(adapterName){
before("Set up databases and initialize persistanz : " + adapterName , function * () {
var dbConf = conf.dbConfigs[adapterName];
dbConf.adapter = adapterName;
yield prepare.createTestDatabase(dbConf);
pers = new Persistanz(dbConf);
var result = yield pers.create();
assert(result === true, "Create should succeed and must return true.");
});
})(adapterName);
after("Destroy persistanz instance", function * () {
yield pers.destroy();
});
/***********************************************************************/
function checkDeleteResult(deleteResult, object, type, id, method) {
["command", "status", "object"].forEach(field => {
assert(field in deleteResult, field + " must be a property in deleteResult.");
});
assert(deleteResult.command === "delete", "command must read delete.");
assert(deleteResult.status === "deleted", "status must read deleted.");
assert(typeof deleteResult.object.id === "number", "deleted object must have a numeric id.");
assert(deleteResult.object.id > 0, "deleted object must have an id.");
//checks with the initial object value. Valid only for pre typecast methods:
if (["pers.deleteObject", "object.delete"].indexOf(method) > -1) {
assert(object.id === deleteResult.object.id, "object id must be the same as that of deleteResult.");
assert(object === deleteResult.object, "delete object is the same object as the original.");
}
assert(deleteResult.object instanceof type, "result object must be of correct type.");
assert(deleteResult.object.id === id, "deleteResult object property must be what we set.");
}
function checkInsertResult(saveResult, object, type, name, method) {
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "insert", "command must read insert.");
assert(saveResult.status === "saved", "status must read saved.");
assert(typeof saveResult.object.id === "number", "saved object must have a numeric id.");
assert(saveResult.object.id > 0, "saved object must have an id.");
//checks with the initial object value. Valid only for pre typecast methods:
if (["pers.save", "pers.insert", "object.save", "object.insert"].indexOf(method) > -1) {
assert(object.id === saveResult.object.id, "object id must be the same as that of saveResult.");
assert(saveResult.lastInsertId === object.id, "lastInsertId must be the same as object id.");
assert(object.name === name, "Object.name should be what we set.");
}
assert(saveResult.object instanceof type, "result object must be of correct type.");
assert(saveResult.object.name === name, "saveResult object property must be what we set.");
}
/***********************************************************************/
describe("insert: promises with pers", function(){
it("pers.save() for insert using promises", function * (){
let c = new pers.m.Customer();
c.name = "Ege Madra";
let saveResult = yield pers.save(c);
checkInsertResult(saveResult, c, pers.m.Customer, "Ege Madra", "pers.save");
});
it("pers.insert() for insert using promises", function * (){
let c = new pers.m.Customer();
c.name = "John Doe";
let saveResult = yield pers.insert(c);
checkInsertResult(saveResult, c, pers.m.Customer, "John Doe", "pers.insert");
});
it("pers.saveAs() for insert using promises", function * (){
var o = {name: "Ege Madra2"}
let saveResult = yield pers.saveAs(o, "Customer");
checkInsertResult(saveResult, o, pers.m.Customer, "Ege Madra2", "pers.saveAs");
});
it("pers.insertAs() for insert using promises", function * (){
var o = {name: "John Doe2"}
let saveResult = yield pers.insertAs(o, "Customer");
checkInsertResult(saveResult, o, pers.m.Customer, "John Doe2", "pers.insertAs");
});
});
describe("insert: promises with model", function(){
it("object.save() for insert using promises", function * (){
let c = new pers.m.Customer();
c.name = "Ege Madra";
let saveResult = yield c.save();
checkInsertResult(saveResult, c, pers.m.Customer, "Ege Madra", "object.save");
});
it("object.insert() for insert using promises", function * (){
let c = new pers.m.Customer();
c.name = "John Doe";
let saveResult = yield c.insert();
checkInsertResult(saveResult, c, pers.m.Customer, "John Doe", "object.insert");
});
it("Model.save() for insert using promises", function * (){
var o = {name: "Ege Madra2"}
let saveResult = yield pers.models.Customer.save(o);
checkInsertResult(saveResult, o, pers.m.Customer, "Ege Madra2", "Model.save");
});
it("Model.insert() for insert using promises", function * (){
var o = {name: "John Doe2"}
let saveResult = yield pers.models.Customer.insert(o);
checkInsertResult(saveResult, o, pers.m.Customer, "John Doe2", "Model.insert");
});
});
describe("insert: callbacks with pers", function() {
it("pers.save() for insert using callbacks", function (done){
let c = new pers.m.Customer();
c.name = "Ege Madra";
pers.save(c, function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, c, pers.m.Customer, "Ege Madra", "pers.save");
done();
});
});
it("pers.insert() for insert using callbacks", function (done){
let c = new pers.m.Customer();
c.name = "John Doe";
pers.insert(c, function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, c, pers.m.Customer, "John Doe", "pers.insert");
done();
});
});
it("pers.saveAs() for insert using callbacks", function (done){
var o = {name: "Ege Madra2"}
pers.saveAs(o, "Customer", function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, o, pers.m.Customer, "Ege Madra2", "pers.saveAs");
done();
});
});
it("pers.insertAs() for insert using callbacks", function (done){
var o = {name: "John Doe2"}
pers.insertAs(o, "Customer", function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, o, pers.m.Customer, "John Doe2", "pers.insertAs");
done();
});
});
});
describe("insert: callbacks with model", function(){
it("object.save() for insert using callback", function (done){
let c = new pers.m.Customer();
c.name = "Ege Madra";
c.save(function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, c, pers.m.Customer, "Ege Madra", "object.save");
done();
});
});
it("object.insert() for insert using callbacks", function (done){
let c = new pers.m.Customer();
c.name = "John Doe";
c.insert(function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, c, pers.m.Customer, "John Doe", "object.insert");
done();
});
});
it("Model.save() for insert using callbacks", function (done){
var o = {name: "Ege Madra2"}
pers.models.Customer.save(o, function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, o, pers.m.Customer, "Ege Madra2", "Model.save");
done();
});
});
it("Model.insert() for insert using callbacks", function (done){
var o = {name: "John Doe2"}
pers.models.Customer.insert(o, function(err, saveResult){
if (err) return done(err);
checkInsertResult(saveResult, o, pers.m.Customer, "John Doe2", "Model.insert");
done();
});
});
});
describe("Inserting into a non-auto-increment pk table", function(){
it("Insert with promise", function * () {
var o = pers.m.Country.cast({code: "USA", name: "United States of America"});
var saveResult = yield o.insert();
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "insert", "command must read insert.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.code === o.code, "pk in the object must be updated.");
assert(saveResult.object.name === o.name, "Object.name should be what we set.");
assert(saveResult.object.code === "USA", "saveResult object code must read USA.");
assert(saveResult.lastInsertId === "USA", "lastInsertId must read the code that we set.");
});
it("Insert with callback", function (done) {
var o = pers.m.Country.cast({code: "GBR", name: "Great Britain"});
o.insert(function(err, saveResult){
assert(err == null, "No err should be present.");
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "insert", "command must read insert.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.code === o.code, "pk in the object must be updated.");
assert(saveResult.object.name === o.name, "Object.name should be what we set.");
assert(saveResult.object.code === "GBR", "saveResult object code must read GBR.");
assert(saveResult.lastInsertId === "GBR", "lastInsertId must read the code that we set.");
done();
});
});
})
describe("insertion errors", function (){
it("Ensure inserts with existing ids throwing (promise)", function * (){
try {
yield pers.insertAs({"id": 1, name: "Ege"}, "Customer");
assert(false, "Inserting with an existing id must throw.");
}
catch(err){
assert(true);
}
});
it("Ensure inserts with existing ids returns error (callback)", function (done){
pers.insertAs({"id": 1, name: "Ege"}, "Customer", function(err, result){
assert(err != null, "Inserting with an existing id must return error.");
assert(result == null, "There must not be a result.");
done();
});
});
it("Inserts without pks to non-auto-increment tables must throw in promise mode", function * (){
try {
yield pers.insertAs({name: "Latvia"}, "Country");
assert(false, "Inserting without a pk to a non auto-increment table must throw.");
}
catch(err){
assert(true);
}
});
it("Inserts without pks to non-auto-increment tables must error in callback mode", function (done){
pers.insertAs({name: "Latvia"}, "Country", function(err, result){
assert(err != null, "Inserting without a pk to a non auto-increment table must error.");
assert(result == null, "There must not be a result.");
done();
});
});
});
describe("Make sure we have 16 customers and 2 countries so far", function() {
it("Get all customers, using repository with promises", function * (){
var customers = yield pers.query().from("Customer").exec();
assert(Array.isArray(customers), ".query() returns an array.");
assert(customers.length === 16, "we must have inserted 16 customers.");
});
it("Get all customers, using model with promises", function * (){
var customers = yield pers.models.Customer.query().exec();
assert(Array.isArray(customers), ".query() returns an array.");
assert(customers.length === 16, "we must have inserted 16 customers.");
});
it("Get all countries, using repository with callbacks", function (done){
pers.query().from("Country").exec(function(err, countries){
assert(err == null, "No errors.");
if (err) done();
assert(Array.isArray(countries), ".query() returns an array.");
assert(countries.length === 2, "we must have inserted 2 countries.");
done();
});
});
it("Get all countries, using model with callbacks", function (done){
pers.models.Country.query().exec(function(err, countries){
assert(err == null, "No errors.");
if (err) done();
assert(Array.isArray(countries), ".query() returns an array.");
assert(countries.length === 2, "we must have inserted 2 countries.");
done();
});
});
});
describe("Make sure basic queries don't throw in callback mode", function () {
it("bad queries with callbacks can't throw", function (done){
var errCount = 0, resultCount = 0;
function cb (err, results) {
if (err != null) errCount ++;
if (results != null) resultCount ++;
};
var Customer = pers.models.Customer;
pers.models.Country.query().select("nonexistentColumn").exec(cb); //1
Customer.insert({}, cb); //2
Customer.save({}, cb); //3
var c = new Customer();
c.save(cb); //4
c.insert(cb); //5
pers.save(new Customer(), cb); //6
pers.saveAs({}, "Customer", cb); //7
pers.insert(new Customer(), cb); //8
pers.insertAs({}, "Customer", cb); //9
pers.models.Country.query().select("nonexistentColumn").one(cb); //10
setTimeout(function(){
assert(errCount === 10, "We must have collected 10 errors by now.");
assert(resultCount === 0, "We must have collected no results by now.");
done();
},50);
});
});
describe("Updates", function () {
var c1 = null;
function * getCustomer1 () {
return c1 = yield pers.q().f("Customer").one();
}
it("pers.save()", function * () {
yield getCustomer1();
c1.name = "Darth Vader";
var saveResult = yield pers.save(c1);
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "update", "command must read update.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.name === "Darth Vader", "Saved object should reflect the new value.")
assert(saveResult.object === c1, "There is only one object!");
});
it("object.save()", function * () {
assert(c1.name === "Darth Vader", "It must be modified now.");
c1.name = "Princess Lea";
var saveResult = yield c1.save();
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "update", "command must read update.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.name === "Princess Lea", "Saved object should reflect the new value.")
assert(saveResult.object === c1, "There is only one object!");
});
it("pers.saveAs()", function * () {
assert(c1.name === "Princess Lea", "It must be modified now.");
var newObject = {id: c1.id, name: "Luke Skywalker"};
var saveResult = yield pers.saveAs(newObject, "Customer");
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "update", "command must read update.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.name === "Luke Skywalker", "Saved object should reflect the new value.")
assert(saveResult.object.id === c1.id, "Although 2 different objects, ids must be the same.");
});
it("Model.save()", function * () {
assert(c1.name === "Princess Lea", "Previous save as should not have touched the original object");
var newObject = {id: c1.id, name: "Han Solo"};
var saveResult = yield pers.models.Customer.save(newObject);
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "update", "command must read update.");
assert(saveResult.status === "saved", "status must read saved.");
assert(saveResult.object.name === "Han Solo", "Saved object should reflect the new value.")
assert(saveResult.object.id === c1.id, "Although 2 different objects, ids must be the same.");
//now validate:
var finalCustomer = yield pers.loadById("Customer", c1.id);
assert(finalCustomer.id === c1.id && finalCustomer.name === "Han Solo", "Just validate.");
});
it("Not update anything", function * () {
const fakeId = 98564;
var saveResult = yield pers.saveAs({id: fakeId, name: "Avarel Dalton"}, "Customer");
["lastInsertId", "command", "status", "object"].forEach(field => {
assert(field in saveResult, field + " must be a property in saveResult.");
});
assert(saveResult.command === "update", "command must read update.");
assert(saveResult.status === "not-saved", "status must read not-saved.");
//validate not saved:
var nullCustomer = yield pers.m.Customer.loadById(fakeId);
assert(nullCustomer === null, "There should be no customer with that id.");
});
});
describe("deletes: pers.deleteById & pers.deleteObject", function() {
it("pers.deleteById with promises", function * (){
var deleteResult = yield pers.deleteById("Customer", 1);
checkDeleteResult(deleteResult, null, pers.models.Customer, 1, "pers.deleteById");
});
it("pers.deleteById with callbacks", function (done){
pers.deleteById("Customer", 2, function(err, deleteResult){
if (err) return done(err);
checkDeleteResult(deleteResult, null, pers.models.Customer, 2, "pers.deleteById");
done();
});
});
it("pers.deleteObject with promises", function * () {
var c = pers.cast({id: 3}, "Customer");
var deleteResult = yield pers.deleteObject(c);
checkDeleteResult(deleteResult, c, pers.models.Customer, 3, "pers.deleteObject");
});
it("pers.deleteObject with callbacks", function (done){
var c = pers.cast({id: 4}, "Customer");
pers.deleteObject(c, function(err, deleteResult){
if (err) return done(err);
checkDeleteResult(deleteResult, c, pers.models.Customer, 4, "pers.deleteObject");
done();
});
});
});
describe("deletes: Model.deleteById & object.delete", function() {
it("Model.deleteById with promises", function * (){
var deleteResult = yield pers.models.Customer.deleteById(5);
checkDeleteResult(deleteResult, null, pers.models.Customer, 5, "Model.deleteById");
});
it("Model.deleteById with callbacks", function (done){
pers.models.Customer.deleteById(6, function(err, deleteResult){
if (err) return done(err);
checkDeleteResult(deleteResult, null, pers.models.Customer, 6, "Model.deleteById");
done();
});
});
it("object.delete with promises", function * () {
var c = pers.cast({id: 7}, "Customer");
var deleteResult = yield c.delete();
checkDeleteResult(deleteResult, c, pers.models.Customer, 7, "object.delete");
});
it("object.delete with callbacks", function (done){
var c = pers.cast({id: 8}, "Customer");
c.delete(function(err, deleteResult){
if (err) return done(err);
checkDeleteResult(deleteResult, c, pers.models.Customer, 8, "object.delete");
done();
});
});
});
describe("not-deleted and validation", function () {
it("Not delete anything", function * () {
const id = 1; //we have already deleted Customer:1 above.
var deleteResult = yield pers.deleteById("Customer", 1);
["command", "status", "object"].forEach(field => {
assert(field in deleteResult, field + " must be a property in deleteResult.");
});
assert(deleteResult.command === "delete", "command must read delete.");
assert(deleteResult.status === "not-deleted", "status must read not-deleted.");
});
it("Validate deletes by confirming we have only 8 customers left", function * (){
var customers = yield pers.models.Customer.q().exec();
assert(customers.length === 8, "We should have 8 customers now.");
});
});
describe("hydrate()", function() {
let saveResult = null, customer = null;
function * prepare () {
saveResult = yield pers.insertAs({name: "James Bond"}, "Customer");
customer = yield pers.loadById("Customer", saveResult.lastInsertId, "id");
assert(customer.id === saveResult.lastInsertId, "customer id must be the same as inserted.");
assert(customer.name === undefined, "We didn't select name field.");
}
it("pers.hydrate() with promises", function * () {
yield prepare();
let newCustomer = yield pers.hydrate(customer);
assert(customer === newCustomer, "They are the same objects.");
assert(customer.name === "James Bond", "original customer is modified must have the name 'James Bond'.");
});
it("object.hydrate() with promises", function * () {
delete customer.name;
let newCustomer = yield customer.hydrate("name");
assert(customer === newCustomer, "They are the same objects.");
assert(customer.name === "James Bond", "original customer is modified must have the name 'James Bond'.");
});
it("pers.hydrate() with callbacks", function (done) {
delete customer.name;
pers.hydrate(customer, "name", function(err, newCustomer){
if (err) return done(err);
assert(customer === newCustomer, "They are the same objects.");
assert(customer.name === "James Bond", "original customer is modified must have the name 'James Bond'.");
done();
});
});
it("object.hydrate() with callbacks", function (done) {
delete customer.name;
customer.hydrate("name", function(err, newCustomer){
if (err) return done(err);
assert(customer === newCustomer, "They are the same objects.");
assert(customer.name === "James Bond", "original customer is modified must have the name 'James Bond'.");
done();
});
});
it("hydrate without pk throws (promises)", function * () {
var c = new pers.models.Customer();
try {
yield c.hydrate("name");
assert(false, "cannot end up here.");
} catch (err) {
assert(err.toString().includes("without the primary key"), "Should tell about the missing pk.");
}
});
it("hydrate without a corresponding row in db throws (promises)", function * () {
var c = pers.cast({id: 2657}, "Customer");
try {
yield c.hydrate("name");
} catch (err) {
assert(err.toString().includes("not found in the database"), "Should tell about the missing row.");
}
});
it("hydrate without pk errors (callbacks)", function (done) {
var c = new pers.models.Customer();
c.hydrate("name", function(err, result){
assert(err.toString().includes("without the primary key"), "Should tell about the missing pk.");
done();
});
});
it("hydrate without a corresponding row in db errors (callbacks)", function (done) {
var c = pers.cast({id: 2657}, "Customer");
c.hydrate("name", function(err, result){
assert(err.toString().includes("not found in the database"), "Should tell about the missing row.");
done();
});
});
});
});
}
});