508 lines
16 KiB
JavaScript
508 lines
16 KiB
JavaScript
define("dstore/tests/Memory", [
|
|
'intern!object',
|
|
'intern/chai!assert',
|
|
'dojo/_base/declare',
|
|
'./sorting',
|
|
'dstore/Memory',
|
|
'dstore/QueryMethod'
|
|
], function (registerSuite, assert, declare, sorting, Memory, QueryMethod) {
|
|
|
|
var store;
|
|
var Model = declare(null, {
|
|
constructor: function (args) {
|
|
declare.safeMixin(this, args);
|
|
}
|
|
});
|
|
|
|
registerSuite({
|
|
name: 'dstore Memory',
|
|
|
|
beforeEach: function () {
|
|
store = new Memory({
|
|
data: [
|
|
{ id: 1, name: 'one', prime: false, mappedTo: 'E', nested: {a: 5} },
|
|
{ id: 2, name: 'two', even: true, prime: true, mappedTo: 'D', nested: {a: 4} },
|
|
{ id: 3, name: 'three', prime: true, mappedTo: 'C', nested: {a: 3} },
|
|
{ id: 4, name: 'four', even: true, prime: false, mappedTo: null , nested: {a: 2}},
|
|
{ id: 5, name: 'five', prime: true, mappedTo: 'A', nested: {a: 1} }
|
|
],
|
|
Model: Model,
|
|
filterFunction: function (object) {
|
|
return object.name === 'two';
|
|
}
|
|
});
|
|
|
|
// add a method to the model prototype
|
|
store.Model.prototype.describe = function () {
|
|
return this.name + ' is ' + (this.prime ? '' : 'not ') + 'a prime';
|
|
};
|
|
},
|
|
|
|
'getSync': function () {
|
|
assert.strictEqual(store.getSync(1).name, 'one');
|
|
assert.strictEqual(store.getSync(4).name, 'four');
|
|
assert.isTrue(store.getSync(5).prime);
|
|
},
|
|
'get': function () {
|
|
return store.get(1).then(function (object) {
|
|
assert.strictEqual(object.name, 'one');
|
|
});
|
|
},
|
|
|
|
'fetchSync and fetchRangeSync results.totalLength': function () {
|
|
var results = store.fetchSync(),
|
|
rangeResults = store.fetchRangeSync({ start: 0, end: 1 });
|
|
|
|
assert.isNumber(results.totalLength);
|
|
assert.isNumber(rangeResults.totalLength);
|
|
|
|
assert(results.totalLength, results.length);
|
|
assert.strictEqual(rangeResults.totalLength, results.totalLength);
|
|
},
|
|
|
|
'Model': function () {
|
|
assert.strictEqual(store.getSync(1).describe(), 'one is not a prime');
|
|
assert.strictEqual(store.getSync(3).describe(), 'three is a prime');
|
|
assert.strictEqual(store.filter({even: true}).fetchSync()[1].describe(), 'four is not a prime');
|
|
},
|
|
|
|
'no Model': function() {
|
|
var noModelStore = new Memory({
|
|
data: [
|
|
{id: 1, name: 'one', prime: false, mappedTo: 'E'}
|
|
],
|
|
Model: null
|
|
});
|
|
assert.strictEqual(noModelStore.getSync(1).get, undefined);
|
|
assert.strictEqual(noModelStore.getSync(1).save, undefined);
|
|
},
|
|
|
|
'filter': function () {
|
|
var filter = new store.Filter();
|
|
assert.strictEqual(store.filter(filter.eq('prime', true)).fetchSync().length, 3);
|
|
var count = 0;
|
|
store.filter(filter.eq('prime', true)).fetch().forEach(function (object) {
|
|
count++;
|
|
assert.equal(object.prime, true);
|
|
});
|
|
assert.equal(count, 3);
|
|
assert.strictEqual(store.filter({even: true}).fetchSync()[1].name, 'four');
|
|
},
|
|
|
|
'async filter': function () {
|
|
var filter = new store.Filter();
|
|
return store.filter(filter.eq('even', true)).fetch().then(function (results) {
|
|
assert.strictEqual(results.length, 2);
|
|
});
|
|
},
|
|
|
|
'filter with string': function () {
|
|
assert.strictEqual(store.filter({name: 'two'}).fetchSync().length, 1);
|
|
assert.strictEqual(store.filter({name: 'two'}).fetchSync()[0].name, 'two');
|
|
},
|
|
|
|
'filter with regexp': function () {
|
|
assert.strictEqual(store.filter({name: /^t/}).fetchSync().length, 2);
|
|
assert.strictEqual(store.filter({name: /^t/}).fetchSync()[1].name, 'three');
|
|
assert.strictEqual(store.filter({name: /^o/}).fetchSync().length, 1);
|
|
assert.strictEqual(store.filter({name: /o/}).fetchSync().length, 3);
|
|
},
|
|
|
|
'filter with or': function () {
|
|
var filter = new store.Filter();
|
|
var primeOrEven = filter.or(filter.eq('prime', true), filter.eq('even', true));
|
|
assert.strictEqual(store.filter(primeOrEven).fetchSync().length, 4);
|
|
},
|
|
|
|
'filter with gt and lt': function () {
|
|
var filter = new store.Filter();
|
|
var betweenTwoAndFour = filter.gt('id', 2).lt('id', 5);
|
|
assert.strictEqual(store.filter(betweenTwoAndFour).fetchSync().length, 2);
|
|
var overTwo = {
|
|
id: filter.gt(2)
|
|
};
|
|
assert.strictEqual(store.filter(overTwo).fetchSync().length, 3);
|
|
var TwoToFour = filter.gte('id', 2).lte('id', 5);
|
|
assert.strictEqual(store.filter(TwoToFour).fetchSync().length, 4);
|
|
},
|
|
|
|
'filter with nested gt and lt': function () {
|
|
var filter = new store.Filter();
|
|
var betweenTwoAndFour = filter.gt('nested.a', 2).lt('nested.a', 5);
|
|
assert.strictEqual(store.filter(betweenTwoAndFour).fetchSync().length, 2);
|
|
var overTwo = {
|
|
'nested.a': filter.gt(2)
|
|
};
|
|
assert.strictEqual(store.filter(overTwo).fetchSync().length, 3);
|
|
var TwoToFour = filter.gte('nested.a', 2).lte('nested.a', 5);
|
|
assert.strictEqual(store.filter(TwoToFour).fetchSync().length, 4);
|
|
},
|
|
|
|
'filter with test function': function () {
|
|
assert.strictEqual(store.filter({id: {test: function (id) {
|
|
return id < 4;
|
|
}}}).fetchSync().length, 3);
|
|
assert.strictEqual(store.filter({even: {test: function (even, object) {
|
|
return even && object.id > 2;
|
|
}}}).fetchSync().length, 1);
|
|
},
|
|
|
|
'filter with sort': function () {
|
|
assert.strictEqual(store.filter({prime: true}).sort('name').fetchSync().length, 3);
|
|
assert.strictEqual(store.filter({even: true}).sort('name').fetchSync()[1].name, 'two');
|
|
assert.strictEqual(store.filter({even: true}).sort(function (a, b) {
|
|
return a.name < b.name ? -1 : 1;
|
|
}).fetchSync()[1].name, 'two');
|
|
assert.strictEqual(store.filter(null).sort('mappedTo').fetchSync()[4].name, 'four');
|
|
},
|
|
|
|
'filter with nested sort': function () {
|
|
assert.strictEqual(store.filter({prime: true}).sort('nested.a').fetchSync().length, 3);
|
|
assert.strictEqual(store.filter({even: true}).sort('nested.a').fetchSync()[1].name, 'two');
|
|
assert.strictEqual(store.filter({'nested.a': 2}).sort('mappedTo').fetchSync()[0].name, 'four');
|
|
},
|
|
|
|
|
|
'filter with paging': function () {
|
|
assert.strictEqual(store.filter({prime: true}).fetchRangeSync({start: 1, end: 2}).length, 1);
|
|
var count = 0;
|
|
store.filter({prime: true}).fetchRange({start: 1, end: 2}).forEach(function (object) {
|
|
count++;
|
|
assert.equal(object.prime, true);
|
|
});
|
|
assert.equal(count, 1);
|
|
assert.strictEqual(store.filter({prime: true}).fetchRangeSync({start: 1, end: 2}).totalLength, 3);
|
|
assert.strictEqual(store.filter({even: true}).fetchRangeSync({start: 1, end: 2})[0].name, 'four');
|
|
},
|
|
|
|
'filter with string-named function': function () {
|
|
assert.strictEqual(store.filter('filterFunction').fetchSync().length, 1);
|
|
},
|
|
|
|
'filter with inheritance': function () {
|
|
var store = new Memory({
|
|
data: [
|
|
{id: 1, name: 'one', prime: false},
|
|
{id: 2, name: 'two', even: true, prime: true}
|
|
],
|
|
getIdentity: function () {
|
|
return 'id-' + this.inherited(arguments);
|
|
},
|
|
newMethod: function () {
|
|
return 'hello';
|
|
}
|
|
});
|
|
var filtered = store.filter({even: true}).sort('name');
|
|
var one = filtered.getSync('id-1');
|
|
one.changed = true;
|
|
filtered.put(one);
|
|
assert.strictEqual(filtered.getIdentity(one), 'id-1');
|
|
assert.strictEqual(filtered.newMethod(), 'hello');
|
|
store.remove('id-1');
|
|
assert.strictEqual(filtered.getSync('id-1'), undefined);
|
|
},
|
|
|
|
'alternate query method': function () {
|
|
var store = new Memory({
|
|
data: [
|
|
{id: 1, name: 'one', prime: false},
|
|
{id: 2, name: 'two', even: true, prime: true, children: [
|
|
{id: 2.1, name: 'two point one', whole: false, even: false},
|
|
{id: 2.2, name: 'two point two', whole: false, even: true},
|
|
{id: 2.3, name: 'two point three', whole: false, even: false}
|
|
]}
|
|
],
|
|
getChildren: new QueryMethod({
|
|
type: 'children',
|
|
querierFactory: function (parent) {
|
|
return function () {
|
|
return parent.children;
|
|
};
|
|
},
|
|
applyQuery: function(newCollection) {
|
|
newCollection.isAChildCollection = true;
|
|
return newCollection;
|
|
}
|
|
})
|
|
});
|
|
// make the children
|
|
var two = store.getSync(2);
|
|
// and test the new query method
|
|
var ids = [];
|
|
var filteredChildren = store.getChildren(two).filter({even: false});
|
|
filteredChildren.forEach(function (child) {
|
|
ids.push(child.id);
|
|
});
|
|
assert.equal(filteredChildren.queryLog.length, 2);
|
|
assert.equal(filteredChildren.queryLog[0].type, 'children');
|
|
assert.equal(filteredChildren.queryLog[1].type, 'filter');
|
|
assert.isTrue(filteredChildren.isAChildCollection);
|
|
assert.deepEqual(ids, [2.1, 2.3]);
|
|
},
|
|
|
|
'put update': function () {
|
|
var four = store.getSync(4);
|
|
four.square = true;
|
|
store.put(four);
|
|
four = store.getSync(4);
|
|
assert.isTrue(four.square);
|
|
},
|
|
|
|
'put new': function () {
|
|
store.put({
|
|
id: 6,
|
|
perfect: true
|
|
});
|
|
assert.isTrue(store.getSync(6).perfect);
|
|
},
|
|
|
|
'put with options.beforeId': function () {
|
|
// Make default put index 0 so it is clear beforeId:null is working
|
|
store.defaultNewToStart = true;
|
|
|
|
store.put({ id: 2 }, { beforeId: 4 });
|
|
store.put({ id: 0 }, { beforeId: null });
|
|
var results = store.fetchSync();
|
|
// Move from a lower source index to a higher destination index because Memory previously had an
|
|
// off-by-one bug where it removing an updated item from a lower index and inserted it one past
|
|
// the correct destination index
|
|
assert.strictEqual(results[2].id, 2);
|
|
assert.strictEqual(results[3].id, 4);
|
|
assert.strictEqual(results[results.length - 1].id, 0);
|
|
},
|
|
|
|
'add with options.beforeId': function () {
|
|
// Make default put index 0 so it is clear beforeId:null is working
|
|
store.defaultNewToStart = true;
|
|
|
|
store.add({ id: 42 }, { beforeId: 3 });
|
|
store.add({ id: 24 }, { beforeId: null });
|
|
var results = store.fetchSync();
|
|
assert.strictEqual(results[2].id, 42);
|
|
assert.strictEqual(results[3].id, 3);
|
|
assert.strictEqual(results[results.length - 1].id, 24);
|
|
},
|
|
|
|
'create and remove': function () {
|
|
var newObject = store.create({
|
|
id: 10,
|
|
name: 'ten'
|
|
});
|
|
assert.strictEqual(store.getSync(10), undefined);
|
|
store.put(newObject);
|
|
assert.isObject(store.getSync(10));
|
|
store.remove(10);
|
|
assert.strictEqual(store.getSync(10), undefined);
|
|
},
|
|
|
|
'add duplicate': function () {
|
|
store.put({
|
|
id: 6,
|
|
perfect: true
|
|
});
|
|
|
|
var succeeded = false;
|
|
store.add({
|
|
id: 6,
|
|
perfect: true
|
|
}).then(function() {
|
|
succeeded = true;
|
|
}, function() {
|
|
// should be rejected as a duplicate
|
|
});
|
|
assert.isFalse(succeeded);
|
|
},
|
|
|
|
'add new': function () {
|
|
store.add({
|
|
id: 7,
|
|
prime: true
|
|
});
|
|
assert.isTrue(store.getSync(7).prime);
|
|
},
|
|
|
|
'remove': function () {
|
|
store.add({
|
|
id: 7,
|
|
prime: true
|
|
});
|
|
assert.isTrue(store.removeSync(7));
|
|
assert.strictEqual(store.getSync(7), undefined);
|
|
},
|
|
|
|
'remove from object': function () {
|
|
var newObject = store.addSync({
|
|
id: 7,
|
|
prime: true
|
|
});
|
|
return store.remove(newObject.id).then(function (result) {
|
|
assert.isTrue(result);
|
|
assert.strictEqual(store.getSync(7), undefined);
|
|
});
|
|
},
|
|
|
|
'remove missing': function () {
|
|
var expectedLength = store.fetchSync().length;
|
|
assert(!store.removeSync(77));
|
|
// make sure nothing changed
|
|
assert.strictEqual(store.fetchSync().length, expectedLength);
|
|
},
|
|
|
|
'put typed object': function () {
|
|
function MyClass() {}
|
|
var myObject = new MyClass();
|
|
myObject.id = 10;
|
|
store.put(myObject);
|
|
// make sure we don't mess up the class of the input
|
|
assert.isTrue(myObject instanceof MyClass);
|
|
// make sure the the object in the store is the right type
|
|
assert.isTrue(store.getSync(10) instanceof store.Model);
|
|
},
|
|
|
|
'filter after changes': function () {
|
|
store.remove(2);
|
|
store.add({ id: 6, perfect: true });
|
|
assert.strictEqual(store.filter({prime: true}).fetchSync().length, 2);
|
|
assert.strictEqual(store.filter({perfect: true}).fetchSync().length, 1);
|
|
},
|
|
|
|
'ItemFileReadStore style data': function () {
|
|
var anotherStore = new Memory({
|
|
data: {
|
|
|
|
items: [
|
|
{name: 'one', prime: false},
|
|
{name: 'two', even: true, prime: true},
|
|
{name: 'three', prime: true}
|
|
],
|
|
identifier: 'name'
|
|
}
|
|
});
|
|
assert.strictEqual(anotherStore.getSync('one').name, 'one');
|
|
assert.strictEqual(anotherStore.filter({name: 'one'}).fetchSync()[0].name, 'one');
|
|
},
|
|
|
|
'add new id assignment': function () {
|
|
var object = {
|
|
random: true
|
|
};
|
|
object = store.addSync(object);
|
|
assert.isTrue(!!object.id);
|
|
},
|
|
|
|
'query results length properties': function () {
|
|
var filteredCollection = store.filter(function (o) {
|
|
return o.id <= 3;
|
|
});
|
|
|
|
var sortedCollection = store.sort('id');
|
|
|
|
var results = store.fetchRangeSync({start: 0, end: 3});
|
|
assert.strictEqual(results.totalLength, 5);
|
|
assert.strictEqual(results.length, 3);
|
|
},
|
|
|
|
'composite key': function () {
|
|
var store = new Memory({
|
|
data: [
|
|
{ x: 1, y: 1, name: '1,1' },
|
|
{ x: 2, y: 1, name: '2,1' },
|
|
{ x: 1, y: 2, name: '1,2' },
|
|
{ x: 2, y: 2, name: '2,2' }
|
|
],
|
|
getIdentity: function (object) {
|
|
return object.x + ',' + object.y;
|
|
}
|
|
});
|
|
assert.equal(store.getSync('1,1').name, '1,1');
|
|
assert.equal(store.getIdentity(store.getSync('1,2')), '1,2');
|
|
store.add({x: 3, y: 2, name: '3,2'});
|
|
assert.equal(store.getSync('3,2').name, '3,2');
|
|
store.put({x: 1, y: 1, name: 'changed'});
|
|
assert.equal(store.getSync('1,1').name, 'changed');
|
|
},
|
|
|
|
'source collection.data does not become subcollection.data': function () {
|
|
// Note: This is not a great test because it tests an implementation detail rather than public interface.
|
|
// However, it is a detail that is unlikely to change and one we've experienced regression with,
|
|
// so we believe it is a value to test it directly here.
|
|
|
|
var sourceCollection = store.filter({ prime: true });
|
|
|
|
sourceCollection.fetchSync();
|
|
assert.isDefined(sourceCollection.data);
|
|
|
|
var subCollection = sourceCollection.filter({ id: 1 });
|
|
subCollection.fetchSync();
|
|
assert.notDeepEqual(sourceCollection.data, subCollection.data);
|
|
},
|
|
|
|
'subclasses can provide initial `data` at runtime': function () {
|
|
var expectedData = [ 1, 2, 3 ];
|
|
|
|
var TestStore = declare(Memory, {
|
|
constructor: function () {
|
|
this.data = expectedData;
|
|
},
|
|
setData: function (data) {
|
|
this.actualData = data;
|
|
this.inherited(arguments);
|
|
}
|
|
});
|
|
|
|
var testStore = new TestStore();
|
|
assert.deepEqual(testStore.actualData, expectedData);
|
|
},
|
|
|
|
'sorting with null and numbers': function () {
|
|
var store = new Memory({
|
|
data: [
|
|
{id: 1, value: 1},
|
|
{id: 2, value: 2},
|
|
{id: 3, value: null},
|
|
{id: 4, value: -1}
|
|
]
|
|
});
|
|
var results = store.sort('value').fetchSync();
|
|
assert.equal(results[0].id, 4);
|
|
assert.equal(results[1].id, 1);
|
|
assert.equal(results[2].id, 2);
|
|
assert.equal(results[3].id, 3);
|
|
var results = store.sort('value', true).fetchSync();
|
|
assert.equal(results[0].id, 3);
|
|
assert.equal(results[1].id, 2);
|
|
assert.equal(results[2].id, 1);
|
|
assert.equal(results[3].id, 4);
|
|
},
|
|
|
|
'sorting with null and strings': function () {
|
|
var store = new Memory({
|
|
data: [
|
|
{id: 1, value: 'a'},
|
|
{id: 2, value: 'b'},
|
|
{id: 3, value: null},
|
|
{id: 4, value: ''}
|
|
]
|
|
});
|
|
var results = store.sort('value').fetchSync();
|
|
assert.equal(results[0].id, 4);
|
|
assert.equal(results[1].id, 1);
|
|
assert.equal(results[2].id, 2);
|
|
assert.equal(results[3].id, 3);
|
|
var results = store.sort('value', true).fetchSync();
|
|
assert.equal(results[0].id, 3);
|
|
assert.equal(results[1].id, 2);
|
|
assert.equal(results[2].id, 1);
|
|
assert.equal(results[3].id, 4);
|
|
},
|
|
|
|
nestedSuite: sorting('dstore Memory sorting', function before(data) {
|
|
return function before() {
|
|
store = new Memory({data: data});
|
|
};
|
|
}, function sort() {
|
|
return store.sort.apply(store, arguments).fetchSync();
|
|
})
|
|
});
|
|
});
|