UNPKG

@harishreddym/baqend

Version:

Baqend JavaScript SDK

1,475 lines (1,293 loc) 60.5 kB
'use strict'; var DB; if (typeof module !== 'undefined') { require('./node'); DB = require('../lib'); } describe('Test crud', function () { var db, db2, deviceType, personType, addressType, childType, emf, metamodel, streetType; before(function () { emf = new DB.EntityManagerFactory({ host: env.TEST_SERVER, tokenStorage: helper.rootTokenStorage }); metamodel = emf.metamodel; return emf.ready().then(function () { deviceType = metamodel.entity('Device'); if (!metamodel.entity('Person')) { metamodel.addType(personType = new DB.metamodel.EntityType('Person', metamodel.entity(Object))); metamodel.addType(childType = new DB.metamodel.EntityType('Child', personType)); metamodel.addType(addressType = new DB.metamodel.EmbeddableType('Address')); metamodel.addType(streetType = new DB.metamodel.EntityType('Street', metamodel.entity(Object))); personType.addAttribute(new DB.metamodel.SingularAttribute('name', metamodel.baseType(String))); personType.addAttribute(new DB.metamodel.SingularAttribute('address', addressType)); personType.addAttribute(new DB.metamodel.SingularAttribute('age', metamodel.baseType(Number))); personType.addAttribute(new DB.metamodel.SingularAttribute('date', metamodel.baseType(Date))); personType.addAttribute(new DB.metamodel.SingularAttribute('sister', personType)); personType.addAttribute(new DB.metamodel.SingularAttribute('child', personType)); childType.addAttribute(new DB.metamodel.SingularAttribute('mother', personType)); childType.addAttribute(new DB.metamodel.SingularAttribute('aunt', personType)); childType.addAttribute(new DB.metamodel.SingularAttribute('father', personType)); childType.addAttribute(new DB.metamodel.ListAttribute('listSiblings', personType)); childType.addAttribute(new DB.metamodel.SetAttribute('setSiblings', personType)); childType.addAttribute(new DB.metamodel.MapAttribute('mapSiblings', personType, personType)); addressType.addAttribute(new DB.metamodel.SingularAttribute('street', streetType)); addressType.addAttribute(new DB.metamodel.SingularAttribute('zip', metamodel.baseType(Number))); streetType.addAttribute(new DB.metamodel.SingularAttribute('name', metamodel.baseType(String))); streetType.addAttribute(new DB.metamodel.SingularAttribute('number', metamodel.baseType(Number))); streetType.addAttribute(new DB.metamodel.SingularAttribute('neighbor', personType)); } else { personType = metamodel.entity('Person'); addressType = metamodel.embeddable('Address'); childType = metamodel.entity('Child'); streetType = metamodel.entity('Street'); } return metamodel.save(); }); }); beforeEach(function () { db = emf.createEntityManager(); db2 = emf.createEntityManager(); return Promise.all([db.ready(), db2.ready()]); }); describe('contains', function () { it('return false for none entity objects', function () { expect(db.contains({})).be.false; expect(db.contains([])).be.false; expect(db.contains(null)).be.false; expect(db.contains(new addressType.typeConstructor())).be.false; }); it('return false for unattached objects', function () { var obj = personType.create(); expect(db.contains(obj)).be.false; obj._metadata.db = db; expect(db.contains(obj)).be.false; }); it('return false for implicit attached objects', function () { var obj = new db.Person(); expect(db.contains(obj)).be.false; }); }); describe('attach', function () { it('should implicit attach object to db', function () { var obj = new db.Person(); expect(obj.id).be.null; expect(db.contains(obj)).be.false; expect(obj._metadata.isAttached).be.true; expect(obj._metadata.db).equals(db); }); it('should not reattach objects to another db', function () { var obj = new db.Person(); expect(function () { obj.attach(db2); }).throw(DB.error.EntityExistsError); expect(obj._metadata.db).equals(db); expect(db2.contains(obj)).be.false; }); it('should ignore attach object to same db', function () { var obj = personType.create(); expect(obj.id).be.null; obj.attach(db); expect(obj.id).be.ok; var id = obj.id; obj.attach(db); expect(obj.id).equals(id); expect(obj._metadata.db).equals(db); expect(db.contains(obj)).be.true; }); it('should attach implicit attached objects to same db', function () { // use user type since the global db may not know our created person schema var obj = deviceType.create(); expect(obj._metadata.db).equals(DB); expect(DB.contains(obj)).be.false; obj.attach(DB); expect(obj._metadata.db).equals(DB); expect(DB.contains(obj)).be.true; }); it('should not reattach implicit attached objects to another db', function () { // use user type since the global db may not know our created person schema var obj = deviceType.create(); expect(obj._metadata.db).equals(DB); expect(function () { obj.attach(db); }).throw(DB.error.EntityExistsError); expect(obj._metadata.db).equals(DB); expect(db.contains(obj)).be.false; }); }); describe('save', function () { it('should save new created object', function () { var person = new db.Person(); return person.save(function (result) { expect(person.id).be.ok; expect(person.version).be.ok; expect(person.createdAt).be.ok; expect(person.updatedAt).be.ok; expect(person._metadata.isPersistent).be.true; expect(person._metadata.isDirty).be.false; expect(person).equals(result); }); }); it('should save new object from JSON', function () { var json = { name: 'TestName', address: { zip: 22527, }, }; var person = db.Person.fromJSON(json); expect(db.util.Metadata.get(person).db).eql(db); return person.save(function (saved) { expect(saved.name).eql(json.name); expect(saved.address.zip).eql(json.address.zip); }); }); it('should not save objects with persistent collections', function () { var obj = new db.Person(); var child = new db.Child({ listSiblings: [obj], setSiblings: new Set([obj]), mapSiblings: new Map([[obj, obj]]), }); var version; return child.save(function (saved) { expect(saved.listSiblings.length).eql(1); expect(saved.setSiblings.size).eql(1); expect(saved.mapSiblings.size).eql(1); version = child.version; return db2.load(child.id); }).then(function (loaded) { return loaded.save(); }).then(function (saved) { expect(saved.version).eq(version); }); }); it('should save dirty objects with empty list', function () { var obj = new db.Person(); var child = new db.Child({ listSiblings: [obj], }); var version; return child.save(function (saved) { expect(saved.listSiblings.length).eql(1); db.detach(child); version = child.version; return db2.load(child.id); }).then(function (loaded) { loaded.listSiblings = []; return loaded.save(); }).then(function (saved) { return db.Child.load(child.id, { refresh: true }); }).then(function (child) { expect(child.listSiblings.length).eq(0); }); }); it('should save dirty objects with empty set', function () { var obj = new db.Person(); var child = new db.Child({ setSiblings: new Set([obj]), }); var version; return child.save(function (saved) { expect(saved.setSiblings.size).eql(1); db.detach(child); version = child.version; return db2.load(child.id); }).then(function (loaded) { loaded.setSiblings.clear(); return loaded.save(); }).then(function (saved) { return db.Child.load(child.id, { refresh: true }); }).then(function (child) { expect(child.setSiblings.size).eq(0); }); }); it('should save dirty objects with empty map', function () { var obj = new db.Person(); var child = new db.Child({ mapSiblings: new Map([[obj, obj]]), }); var version; return child.save(function (saved) { expect(saved.mapSiblings.size).eql(1); db.detach(child); version = child.version; return db2.load(child.id); }).then(function (loaded) { loaded.mapSiblings.clear(); return loaded.save(); }).then(function (saved) { return db.Child.load(child.id, { refresh: true }); }).then(function (child) { expect(child.mapSiblings.size).eq(0); }); }); it('should save existing object from JSON', function () { var json = { id: '/db/Person/' + db.util.uuid(), name: 'TestName', address: { zip: 22527, }, }; var person = db.Person.fromJSON(json); expect(db.util.Metadata.get(person).db).eql(db); return person.save(function (saved) { expect(saved.id).eqls(json.id); expect(saved.name).eqls(json.name); expect(saved.address.zip).eqls(json.address.zip); }); }); it('should save and refresh object', function () { var person = new db.Person(); person.name = 'Old Name'; var promise = expect(person.save({ refresh: true })).eventually.have.property('name', 'Old Name'); person.name = 'New Name'; return promise; }); it('should save a second time', function () { var person = new db.Person(); var version; return person.save(function () { version = person._metadata.version; person.name = 'Paul Panther'; expect(person._metadata.isDirty).be.true; return person.save(); }).then(function () { expect(person._metadata.version).not.equals(version); expect(person.name).equals('Paul Panther'); }); }); it('should not save a stale object', function () { var person = new db2.Person(); return expect(person.save().then(function () { return db.Person.load(person._metadata.id).then(function (person2) { person2.name = 'Peter Parker'; return person2.save(); }); }).then(function () { person.name = 'Alice Ford'; return person.save(); })).be.rejected.then(function (e) { expect(e).instanceOf(DB.error.PersistentError); return expect(db.Person.load(person._metadata.id)).eventually.have.property('name', 'Peter Parker'); }); }); it('should forcibly save a stale object', function () { var person = new db2.Person(); return person.save().then(function () { return db.Person.load(person.id).then(function (person2) { person2.name = 'Peter Parker'; return person2.save(); }); }).then(function () { person.name = 'Alice Ford'; return person.save({ force: true }); }).then(function () { return db.Person.load(person.id).then(function (person2) { expect(person2.name).equals('Alice Ford'); }); }); }); it('should not override an object that exists', function () { var person = new db2.Person(); return person.save().then(function () { var newPerson = new db.Person(); newPerson.id = person.id; return expect(newPerson.save()).rejected; }); }); it('should forcibly override an object that exists', function () { var person = new db2.Person(); return person.save().then(function () { var newPerson = new db.Person(); newPerson.name = 'Peter Parker'; newPerson.id = person.id; return newPerson.save({ force: true }); }).then(function () { return db.Person.load(person.id).then(function (person2) { expect(person2.name).equals('Peter Parker'); }); }); }); it('should not save an deleted object', function () { var person = new db.Person(); return person.save().then(function () { return db2.Person.load(person.id).then(function (person2) { return person2.delete(); }); }).then(function () { person.name = 'New Name'; return expect(person.save()).rejected; }); }); it('should forcibly save an deleted object', function () { var person = new db.Person(); return person.save().then(function () { return db2.Person.load(person.id).then(function (person2) { return person2.delete(); }); }).then(function () { person.name = 'Peter Parker'; return person.save({ force: true }); }).then(function () { return db.Person.load(person.id).then(function (person2) { expect(person2.name).equals('Peter Parker'); }); }); }); it('should not be allowed to call save twice', function () { var person = new db.Person(); person.save(); expect(person.save.bind(person)).to.throw(Error); }); it('should not save and overwrite afterward changed values', function () { var person = new db.Person(); person.name = 'Old Name'; var promise = person.save(); person.name = 'New Name'; return promise.then(function () { expect(person._metadata.isDirty).be.true; expect(person.name).equals('New Name'); }); }); it('should not save afterward changed values but refrehs it', function () { var person = new db.Person(); person.name = 'Old Name'; var promise = person.save({ refresh: true }); person.name = 'New Name'; return promise.then(function () { expect(person._metadata.isDirty).be.false; expect(person.name).equals('Old Name'); }); }); describe('optimisticSave', function () { it('should retry if the object is out of date', function () { var person = new db2.Person(); var newPerson; var i = 0; return person.save().then(function () { return db.Person.load(person.id); }).then(function (per) { newPerson = per; newPerson.name = 'Peter Parker'; person.name = 'New Name'; return person.save(); }).then(function () { return newPerson.optimisticSave(function (optimisticPerson) { i += 1; optimisticPerson.name = i; }); }) .then(function (result) { expect(result.name).equals(2); expect(result.version).equals(3); }); }); it('should be allowed to abort the process', function () { var person = new db2.Person(); var newPerson; var i = 0; return person.save().then(function () { return db.Person.load(person.id); }).then(function (per) { newPerson = per; newPerson.name = 'Peter Parker'; person.name = 'New Name'; return person.save(); }).then(function () { return newPerson.optimisticSave(function (optimisticPerson, abort) { i += 1; if (i === 2) { return abort(); } optimisticPerson.name = i; }); }) .then(function (result) { expect(result.name).equals('New Name'); expect(result.version).equals(2); }); }); it('should be allowed to return a promise', function () { var person = new db2.Person(); var newPerson; var otherPerson = new db2.Person(); otherPerson.name = 'OtherName'; return otherPerson.save().then(function () { return person.save(); }).then(function () { return db.Person.load(person.id); }).then(function (per) { newPerson = per; newPerson.name = 'Peter Parker'; person.name = 'New Name'; return person.save(); }) .then(function () { return newPerson.optimisticSave(function (optimisticPerson) { return db.Person.load(otherPerson.id).then(function (loadedOtherPerson) { optimisticPerson.name = loadedOtherPerson.name; }); }); }) .then(function (result) { expect(result.name).equals('OtherName'); expect(result.version).equals(3); }); }); }); }); describe('get', function () { var person; beforeEach(function () { person = new db.Person(); person.name = 'Peter Mueller'; person.age = 42; person.date = new Date('1976-11-13'); return person.save(function (saved) { expect(saved).equals(person); expect(saved.id).be.ok; expect(saved.version).be.ok; expect(saved._metadata.isPersistent).be.true; expect(saved._metadata.isDirty).be.false; }); }); it('should retrieved object', function () { return db.Person.load(person.id).then(function (loaded) { expect(loaded).be.ok; expect(loaded.id).equals(person.id); expect(loaded.name).equals('Peter Mueller'); expect(loaded.age).equals(42); expect(loaded.date).eql(new Date('1976-11-13')); }); }); it('should get object reference', function () { var obj1 = db.getReference(person.id); var obj2 = db.Person.ref(person.id); var obj3 = db.Person.ref(person.key); var obj4 = db2.getReference(person.id); var obj5 = db2.Person.ref(person.id); var obj6 = db2.Person.ref(person.key); expect(obj1).be.ok; expect(obj2).be.ok; expect(obj3).be.ok; expect(obj4).be.ok; expect(obj5).be.ok; expect(obj6).be.ok; // Check loaded reference is loaded expect(obj1.id).equals(person.id); expect(obj1.name).equals('Peter Mueller'); expect(obj1.age).equals(42); expect(obj1.date).eql(new Date('1976-11-13')); // Check references are the same expect(obj1 === obj2).true; expect(obj1 === obj3).true; expect(obj4 === obj5).true; expect(obj4 === obj6).true; // Check loaded/unloaded references are not the same expect(obj1 === obj4).false; // Check ids match expect(obj1.id).equals(obj4.id); // Check unloaded reference is not loaded expect(function () { obj4.name; }).to.throw('This object ' + person.id + ' is not available.'); }); it('should get referencing classes', function () { var refs, array; // Test w/o class filter refs = personType.getReferencing(db); expect(refs).to.be.instanceof(Map); array = Array.from(refs); expect(array).to.have.a.lengthOf(3); var obj = {}; array.forEach(function (i) { obj[i[0].name] = Array.from(i[1]); }); expect(obj).to.eql({ Person: ['sister', 'child'], Child: ['mother', 'aunt', 'father', 'listSiblings', 'setSiblings', 'mapSiblings'], Street: ['neighbor'], }); // Test with class filter and inheritance refs = personType.getReferencing(db, { classes: ['/db/Child'] }); expect(refs).to.be.instanceof(Map); array = Array.from(refs); expect(array).to.have.a.lengthOf(2); obj = {}; array.forEach(function (i) { obj[i[0].name] = Array.from(i[1]); }); expect(obj).to.eql({ Person: ['sister', 'child'], Child: ['mother', 'aunt', 'father', 'listSiblings', 'setSiblings', 'mapSiblings'], }); // Test with class filter and no inheritance refs = personType.getReferencing(db, { classes: ['/db/Street'] }); expect(refs).to.be.instanceof(Map); array = Array.from(refs); expect(array).to.have.a.lengthOf(1); obj = {}; array.forEach(function (i) { obj[i[0].name] = Array.from(i[1]); }); expect(obj).to.eql({ Street: ['neighbor'], }); }); it('should get referencing objects', function () { var underTest = new db.Person(); var p1 = new db.Person(); var p2 = new db.Child(); var p3 = new db.Child(); var p4 = new db.Street(); p1.sister = underTest; p2.listSiblings = [underTest]; p3.setSiblings = new Set([underTest]); p4.neighbor = underTest; return Promise.all([underTest.save(), p1.save(), p2.save(), p3.save(), p4.save()]).then(function () { var p = underTest.getReferencing(); expect(p).to.be.instanceof(Promise); return p; }).then(function (refs) { expect(refs).to.be.instanceof(Array); expect(refs).to.have.a.lengthOf(4); expect(refs).to.include(p1); expect(refs).to.include(p2); expect(refs).to.include(p3); expect(refs).to.include(p4); return underTest.getReferencing({ classes: ['/db/Street'] }); }).then(function (refs) { expect(refs).to.be.instanceof(Array); expect(refs).to.have.a.lengthOf(1); expect(refs).to.not.include(p1); expect(refs).to.not.include(p2); expect(refs).to.not.include(p3); expect(refs).to.include(p4); }); }); it('should retrieved same version in same db context', function () { var p1 = db.Person.load(person.id); var p2 = db.Person.load(person.id); return Promise.all([p1, p2]).then(function (loaded) { expect(loaded[0]).be.ok; expect(loaded[0]).equals(loaded[1]); }); }); it('should refresh if the object is stale', function () { person.name = 'Tom Miller'; return db2.Person.load(person.id).then(function (person2) { expect(person2.name).equals('Peter Mueller'); person2.name = 'Alice Ford'; return person2.save(); }).then(function (person2) { return db.refreshBloomFilter().then(function () { return db.Person.load(person.id); }).then(function (person3) { expect(person3).equals(person); expect(person3.name).equals('Alice Ford'); expect(person3.version).equals(person2.version); }); }); }); it('should not refresh local state (static load with option)', function () { person.name = 'Tom Miller'; return db.Person.load(person.id, { local: true }).then(function (obj) { expect(obj.name).equals('Tom Miller'); }); }); it('should not refresh local state', function () { person.name = 'Tom Miller'; return person.load().then(function (obj) { expect(obj.name).equals('Tom Miller'); }); }); it('should refresh local state', function () { person.name = 'Tom Miller'; return person.load({ refresh: true }).then(function (obj) { expect(obj.name).equals('Peter Mueller'); }); }); it('should refresh with static load', function () { person.name = 'Tom Miller'; return db.Person.load(person.id).then(function (obj) { expect(obj.name).equals('Peter Mueller'); }); }); it('should retrieved different version in different db context', function () { var p1 = db.Person.load(person.id); var p2 = db2.Person.load(person.id); return Promise.all([p1, p2]).then(function (loaded) { expect(loaded[0]).not.equals(loaded[1]); }); }); }); describe('delete', function () { var person; beforeEach(function () { person = new db.Person(); person.name = 'Peter Mueller'; person.age = 42; person.date = new Date('1976-11-13'); return person.save(); }); it('should delete object from database', function () { return person.delete().then(function (deleted) { expect(person).eqls(deleted); return expect(db.Person.load(person.id)).become(null); }); }); it('should delete object from EntityManager', function () { expect(db.contains(person)).be.true; return person.delete().then(function () { expect(db.contains(person)).be.false; }); }); it('should mark as dirty', function () { return person.delete().then(function (deleted) { expect(deleted._metadata.isDirty).be.true; }); }); it('should delete version', function () { return person.delete().then(function (deleted) { expect(deleted.version).be.null; }); }); it('should be allowed to save after delete', function () { return person.delete().then(function (per) { return per.save(); }).then(function (saved) { expect(saved.id).be.ok; expect(saved.version).be.ok; expect(saved._metadata.isPersistent).be.true; expect(saved._metadata.isDirty).be.false; return db.Person.load(saved.id); }).then(function (loaded) { expect(loaded).be.ok; expect(loaded.id).equals(person.id); expect(loaded.name).equals('Peter Mueller'); expect(loaded.age).equals(42); expect(loaded.date).eql(new Date('1976-11-13')); }); }); it('should be allowed to delete an object without id', function () { return expect(person.delete().then(function (per) { return per.delete(); })).be.rejectedWith(DB.error.IllegalEntityError); }); it('should be allowed to forcly delete an object without id', function () { return expect(person.delete().then(function (per) { return per.delete({ force: true }); })).be.fulfilled; }); it('should not be allowed to add deleted objects with same id', function () { return expect(person.delete().then(function () { db.attach(person); var newPerson = new db.Person(); newPerson.id = person.id; return db.attach(newPerson); })).be.rejectedWith(DB.error.EntityExistsError); }); it('should not be allowed to delete outdated object', function () { var person = new db2.Person(); return expect(person.save().then(function () { return db.Person.load(person.id); }).then(function (person2) { person2.name = 'Foo Bar'; return person2.save(); }).then(function () { return person.delete(); })).be.rejected; }); it('should be allowed to forcibly delete outdated object', function () { var person = new db2.Person(); return person.save().then(function () { return db.Person.load(person.id); }).then(function (person2) { person2.name = 'Foo Bar'; return person2.save(); }).then(function () { return person.delete({ force: true }); }) .then(function () { return expect(db.Person.load(person.id)).become(null); }); }); }); describe('update', function () { var person; beforeEach(function () { person = new db.Person(); person.name = 'Peter Mueller'; person.age = 42; person.date = new Date('1976-11-13'); return person.save(function (saved) { expect(saved).equals(person); expect(saved.id).be.ok; expect(saved.version).be.ok; expect(saved._metadata.isPersistent).be.true; expect(saved._metadata.isDirty).be.false; }); }); it('should update object', function () { person.name = 'New Name'; return person.update().then(function () { expect(person.name).equals('New Name'); return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }); }); it('should update refresh metadata', function () { person.name = 'New Name'; expect(person.version).equals(1); return person.update().then(function () { expect(person.id).be.ok; expect(person.version).equals(2); expect(person.acl).be.ok; expect(person.createdAt).lt(person.updatedAt); expect(person.updatedAt).gt(new Date(Date.now() - 10 * 60 * 1000)); expect(person.updatedAt).lt(new Date(Date.now() + 10 * 60 * 1000)); }); }); it('should update and refresh object', function () { person.name = 'New Name'; var promise = expect(person.update({ refresh: true })).eventually.have.property('name', 'New Name'); person.name = 'Newer Name'; return promise; }); it('should not allowed to update outdated object', function () { var person = new db2.Person(); return expect(person.save().then(function () { return db.Person.load(person.id); }).then(function (person2) { person2.name = 'Foo Bar'; return person2.save(); }).then(function () { person.name = 'New Name'; return person.update(); })).be.rejected; }); it('should allowed to forcibly update outdated object', function () { var person = new db2.Person(); return person.save().then(function () { return db.Person.load(person.id); }).then(function (person2) { person2.name = 'Foo Bar'; return person2.save(); }).then(function () { person.name = 'New Name'; return person.update({ force: true }); }) .then(function () { return db.Person.load(person.id); }) .then(function (loaded) { expect(loaded.name).equals('New Name'); expect(loaded.version).equals(3); }); }); it('should not be allowed to insert document by update', function () { expect(function () { new db.Person().update(); }).throw(Error); }); }); describe('insert', function () { it('should insert object', function () { var person = new db.Person(); person.name = 'Peter Insert'; return person.insert().then(function () { return expect(db.Person.load(person.id)).become(person); }); }); it('should update metadata', function () { var person = new db.Person(); person.name = 'Peter Insert'; return person.insert().then(function () { expect(person.id).be.ok; expect(person.version).equals(1); expect(person.acl).be.ok; expect(person.createdAt).gt(new Date(Date.now() - 10 * 60 * 1000)); expect(person.createdAt).lt(new Date(Date.now() + 10 * 60 * 1000)); expect(person.updatedAt).gt(new Date(Date.now() - 10 * 60 * 1000)); expect(person.updatedAt).lt(new Date(Date.now() + 10 * 60 * 1000)); }); }); it('should insert and refresh object', function () { var person = new db.Person(); person.name = 'Peter Insert'; var promise = expect(person.insert({ refresh: true })).eventually.have.property('name', 'Peter Insert'); person.name = 'New Peter Insert'; return promise; }); it('should not be allowed to insert loaded object', function () { var person = new db.Person(); person.name = 'Peter Insert'; return person.insert().then(function () { return db.Person.load(person.id); }).then(function (loaded) { loaded.name = 'Peter Inserted'; expect(function () { loaded.insert(); }).throw(Error); }); }); it('should not be allowed to insert existing object', function () { var person = new db2.Person(); return person.save().then(function (saved) { var newPerson = new db.Person(); newPerson.name = 'Blub'; newPerson.id = saved.id; return expect(newPerson.insert()).rejected; }); }); }); describe('load', function () { it('should load modified object', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save().then(function () { return db2.Person.load(person.id); }).then(function (loaded) { loaded.name = 'New Name'; return loaded.save(); }).then(function () { return db.refreshBloomFilter(); }) .then(function () { expect(person).have.property('name', 'Old Name'); return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }); }); it('should load and refresh object with same version', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save(function () { return db2.Person.load(person.id, { refresh: true }); }).then(function (loaded) { loaded.name = 'New Name'; return loaded.save(); }).then(function () { person._metadata.version = 2; expect(person).have.property('name', 'Old Name'); return expect(db.Person.load(person.id, { refresh: true })).eventually.have.property('name', 'New Name'); }).then(function () { return expect(person.load({ refresh: true })).eventually.have.property('name', 'New Name'); }); }); it('should not find deleted object', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save().then(function (obj) { return obj.delete(); }).then(function () { return db.Person.load(person.id); }).then(function (obj) { return expect(obj).be.null; }); }); it('should should clear deleted object locally', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save().then(function (obj) { return obj.delete(); }).then(function () { return person.load(); }).then(function (obj) { return expect(obj).be.null; }); }); it('should load object when deleted', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save().then(function (obj) { return db2.Person.load(person.id); }).then(function (loaded) { return loaded.delete(); }).then(function (obj) { return db.refreshBloomFilter(); }) .then(function () { return db.Person.load(person.id); }) .then(function (obj) { return expect(obj).be.null; }); }); }); describe('client caching', function () { // no client caching in node if (helper.isNode || !DB.util.atob) { it('should disable bloomfilter in node', function () { var em = emf.createEntityManager(); expect(em.isCachingDisabled).be.true; }); return; } // no client caching in phantom if (helper.isPhantomJS) { return; } before(function () { return emf.createEntityManager().code.saveCode('updatePerson', 'module', function (module, exports) { exports.call = function (db, data) { var objId = data.id; var newValue = data.value; return db.Person.load(objId).then(function (person) { person.name = newValue; return person.save(); }); }; }); }); it('should refresh', function () { var person = new db.Person(); person.name = 'Old Name'; return person.save(function () { }).then(function () { return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }).then(function () { return db.refreshBloomFilter(); }) .then(function () { return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }); }); it('should automatically refresh bloom filter', function () { var person = new db.Person(); person.name = 'Old Name'; db.bloomFilterRefresh = 1; var oldBFDate = db.bloomFilter.creation; return person.save(function () { }).then(function () { expect(db.bloomFilter.contains(person.id)).not.be.true; return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }).then(function () { return helper.sleep(1000); }) .then(function () { return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }) .then(function () { db.bloomFilterRefresh = 60; return helper.sleep(200); }) .then(function () { expect(db.bloomFilter.creation).not.equals(oldBFDate); expect(db.bloomFilter.contains(person.id)).be.true; }); }); it('should find ids with special characters in bloom filter', function () { var person = new db.Person(); person.id = helper.randomize('1 1;,/?:@&=+$#-_.!~*\\\'()'); person.name = 'Old Name'; return person.save(function () { }).then(function () { return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }).then(function () { return db.refreshBloomFilter(); }) .then(function () { expect(db.bloomFilter.contains(person.id)).be.true; return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }); }); it('should disable cache during bloom filter refresh', function () { var person = new db.Person(); person.name = 'Old Name'; db.bloomFilterRefresh = 1; var oldBFDate = db.bloomFilter.creation; return person.save(function () { }).then(function () { return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }).then(function () { return helper.sleep(1500); }) .then(function () { expect(db.bloomFilter.creation).equals(oldBFDate); return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }) .then(function () { db.bloomFilterRefresh = 60; }); }); it('should use browser cache', function () { var person = new db.Person(); person.name = 'Old Name'; return db.refreshBloomFilter().then(function () { return person.save(); }).then(function () { return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }) .then(function () { return expect(db.Person.load(person.id)).eventually.have.property('name', 'Old Name'); }); }); it('should use cache white listing', function () { var person = new db.Person(); person.name = 'Old Name'; return db.refreshBloomFilter().then(function () { return person.save(); }).then(function () { return db.Person.load(person.id); }).then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'New Name' }); }) .then(function () { return db.refreshBloomFilter(); }) .then(function () { // BloomFilter forces revalidation. return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }) .then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'Very New Name' }); }) .then(function () { // Now the object must be on the cache white list return expect(db.Person.load(person.id)).eventually.have.property('name', 'New Name'); }); }); it('should use cache black listing', function () { var person = new db.Person(); person.name = 'Old Name'; return db.refreshBloomFilter().then(function () { return person.save(); }).then(function () { return expect(db.Person.load(person.id)).eventually.have.property('name', 'Old Name'); }).then(function () { return db.Person.load(person.id); }) .then(function (loaded) { loaded.name = 'New Name'; // adds the obj to the blacklist. return loaded.save(); }) .then(function () { // updates the object again return db.modules.post('updatePerson', { id: person.id, value: 'Very New Name' }); }) .then(function () { // loads the obj from sever and removes it from the blacklist. return expect(db.Person.load(person.id)).eventually.have.property('name', 'Very New Name'); }) .then(function () { return db.modules.post('updatePerson', { id: person.id, value: 'Extremely New Name' }); }) .then(function () { // Now the object must be loaded from cache again return expect(db.Person.load(person.id)).eventually.have.property('name', 'Very New Name'); }); }); }); describe('depth', function () { var child, father, mother, sister, street, address, sibs; beforeEach(function () { child = new db.Child(); father = new db.Person(); mother = new db.Person(); sister = new db.Person(); street = new db.Street(); address = new db.Address(); sister.name = 'Schwester Meier'; sister.age = 44; mother.name = 'Hildegard Meier'; mother.age = 56; father.name = 'Franz Meier'; father.age = 60; child.name = 'Peter Meier'; child.age = 13; street.name = 'Vogt-Kölln-Straße'; street.number = 30; address.street = street; address.zip = 22527; address.number = 30; father.sister = sister; father.child = child; child.address = address; child.mother = mother; child.aunt = mother; child.father = father; child.listSiblings = new DB.List(); child.setSiblings = new DB.Set(); child.mapSiblings = new DB.Map(); sibs = []; for (var i = 0; i < 6; i += 1) { var sib = new db.Person(); sib.name = 'sib' + i; sibs.child = child; sibs.sister = mother; sibs.address = address; sibs.push(sib); } child.listSiblings.push(sibs[0]); child.listSiblings.push(sibs[1]); child.setSiblings.add(sibs[2]); child.setSiblings.add(sibs[3]); child.mapSiblings.set(sibs[4], sibs[5]); }); it('should save and convert result to JSON', function () { return child.save({ depth: true }).then(function (saved) { var json = saved.toJSON(); expect(json.aunt).eqls(mother.id); expect(json.name).eqls(child.name); expect(json.id).eqls(child.id); expect(json.version).eqls(child.version); expect(json.acl).be.ok; expect(Date.parse(json.createdAt)).eqls(child.createdAt.getTime()); expect(Date.parse(json.updatedAt)).eqls(child.updatedAt.getTime()); }); }); it('should save and convert result excluding metadata to JSON', function () { return child.save({ depth: true }).then(function (saved) { var json1 = saved.toJSON(true); expect(json1.aunt).eqls(mother.id); expect(json1.name).eqls(child.name); expect(json1.id).be.not.ok; expect(json1.version).be.not.ok; expect(json1.acl).be.not.ok; expect(json1.createdAt).be.not.ok; expect(json1.updatedAt).be.not.ok; var json2 = saved.toJSON({ excludeMetadata: true }); expect(json2.aunt).eqls(mother.id); expect(json2.name).eqls(child.name); expect(json2.id).be.not.ok; expect(json2.version).be.not.ok; expect(json2.acl).be.not.ok; expect(json2.createdAt).be.not.ok; expect(json2.updatedAt).be.not.ok; var json3 = saved.toJSON({ depth: 1, excludeMetadata: true }); expect(json3.name).eqls(child.name); expect(json3.id).be.not.ok; expect(json3.version).be.not.ok; expect(json3.acl).be.not.ok; expect(json3.createdAt).be.not.ok; expect(json3.updatedAt).be.not.ok; expect(json3.aunt.name).eqls('Hildegard Meier'); expect(json3.aunt.id).be.not.ok; expect(json3.aunt.version).be.not.ok; expect(json3.aunt.acl).be.not.ok; expect(json3.aunt.createdAt).be.not.ok; expect(json3.aunt.updatedAt).be.not.ok; }); }); it('should save and convert result by JSON.stringify to JSON', function () { return child.save({ depth: true }).then(function (saved) { var jsonString = JSON.stringify({ obj: saved }); var json = JSON.parse(jsonString).obj; expect(json).be.ok; expect(json.aunt).eqls(mother.id); expect(json.name).eqls(child.name); expect(json.id).eqls(child.id); expect(json.version).eqls(child.version); expect(json.acl).be.ok; expect(Date.parse(json.createdAt)).eqls(child.createdAt.getTime()); expect(Date.parse(json.updatedAt)).eqls(child.updatedAt.getTime()); }); }); it('should save and delete referenced objects by depth', function () { return child.save({ depth: 2 }).then(function () { var promises = [ expect(db.Child.load(child.id)).not.become(null), expect(db.Person.load(mother.id)).not.become(null), expect(db.Person.load(father.id)).not.become(null), expect(db.Street.load(street.id)).not.become(null), expect(db.Person.load(sister.id)).not.become(null), ]; sibs.forEach(function (sib) { promises.push(expect(db.Person.load(sib.id)).not.become(null)); }); return Promise.all(promises); }).then(function () { return child.delete({ depth: 2 }); }).then(function (deleted) { expect(deleted).equals(child); var promises = [ expect(db.Child.load(child.id)).become(null), expect(db.Person.load(mother.id)).become(null), expect(db.Person.load(father.id)).become(null), expect(db.Street.load(street.id)).become(null), expect(db.Person.load(sister.id)).become(null), ]; sibs.forEach(function (sib) { promises.push(expect(db.Person.load(sib.id)).become(null)); }); return Promise.all(promises); }); }); it('should save and delete referenced objects by reachability', function () { return child.save({ depth: true }).then(function () { var promises = [ expect(db.Child.load(child.id)).not.become(null), expect(db.Person.load(mother.id)).not.become(null), expect(db.Person.load(father.id)).not.become(null), expect(db.Street.load(street.id)).not.become(null), expect(db.Person.load(sister.id)).not.become(null), ]; sibs.forEach(function (sib) { promises.push(expect(db.Person.load(sib.id)).not.become(null)); }); return Promise.all(promises); }).then(function () { return child.delete({ depth: true }); }).then(function (deleted) { expect(deleted).equals(child); var promises = [ expect(db.Child.load(child.id)).become(null), expect(db.Person.load(mother.id)).become(null), expect(db.Person.load(father.id)).become(null), expect(db.Street.load(street.id)).become(null), expect(db.Person.load(sister.id)).become(null), ]; sibs.forEach(function (sib) { promises.push(expect(db.Person.load(sib.id)).become(null)); }); return Promise.all(promises); }); }); it('should get referenced objects by depth', function () { return child.save({ depth: true }).then(function (saved) { child = saved; sibs.forEach(function (sib) { expect(db2.containsById(sib)).be.false; }); expect(db2.containsById(father)).be.false; expect(db2.containsById(sister)).be.false; expect(db2.containsById(mother)).be.false; expect(db2.containsById(street)).be.false; return db2.Child.load(child.id, { depth: 2 }); }).then(function (loaded) { expect(loaded.father.sister._metadata.isAvailable).be.true; expect(loaded.father._metadata.isAvailable).be.true; expect(loaded.mother._metadata.isAvailable).be.true; expect(loaded.address.street._metadata.isAvailable).be.true; expect(loaded.father.name).eqls(father.name); expect(loaded.father.sister.name).eqls(sister.name); expect(loaded.mother.name).eqls(mother.name); expect(loaded.address.street.name).eqls(street.name); }); }); it('should get referenced objects by reachability', function () { return child.save({ depth: true }).then(function (saved) { child = saved; expect(db2.containsById(father)).be.false; expect(db2.containsById(sister)).be.false; expect(db2.containsById(mother)).be.false; expect(db2.containsById(street)).be.false; return db2.Child.load(child.id, { depth: true }); }).then(function (loaded) { expect(loaded.father.sister._metadata.isAvailable).be.true; expect(loaded.father._metadata.isAvailable).be.true; expect(loaded.mother._metadata.isAvailable).be.true; expect(loaded.address.street._metadata.isAvailable).be.true; expect(loaded.father.name).eqls(father.name); expect(loaded.father.sister.name).eqls(sister.name); expect(loaded.mother.name).eqls(mother.name); expect(loaded.address.street.name).eq