Changeset View
Changeset View
Standalone View
Standalone View
lib/chip-types/datastore.js
"use strict"; | |||||
const locreq = require("locreq")(__dirname); | const locreq = require("locreq")(__dirname); | ||||
const assert = require("assert"); | const assert = require("assert"); | ||||
const Chip = require("./chip.js"); | const Chip = require("./chip.js"); | ||||
const Promise = require("bluebird"); | const Promise = require("bluebird"); | ||||
const Errors = locreq("lib/response/error.js"); | const Errors = locreq("lib/response/error.js"); | ||||
const Datastore = function(app, declaration) { | const Datastore = function(app, declaration) { | ||||
this.name = declaration.name; | this.name = declaration.name; | ||||
this.longid = `${Datastore.type_name}.${this.name}`; | this.longid = `${Datastore.type_name}.${this.name}`; | ||||
}; | }; | ||||
Datastore.type_name = "datastore"; | Datastore.type_name = "datastore"; | ||||
Datastore.prototype = new Chip(); | Datastore.prototype = new Chip(); | ||||
const needs_to_implement = ["find", "insert", "update", "remove"]; | |||||
Datastore.prototype.return_not_implemented = function(fn_name) { | Datastore.prototype.return_not_implemented = function(fn_name) { | ||||
return function() { | return function() { | ||||
throw new Errors.DeveloperError( | throw new Errors.DeveloperError( | ||||
"Function ", | "Function ", | ||||
fn_name, | fn_name, | ||||
"not implemented in ", | "not implemented in ", | ||||
this.longid, | this.longid, | ||||
", aborting." | ", aborting." | ||||
); | ); | ||||
}; | }; | ||||
}; | }; | ||||
/* | /* | ||||
Tests datastore compatibility with Sealious. It is a cascade of Promises, which result will be logged in console. | Tests datastore compatibility with Sealious. It is a cascade of Promises, which result will be logged in console. | ||||
*/ | */ | ||||
Datastore.prototype.test_compatibility = function() { | Datastore.prototype.test_compatibility = function() { | ||||
const self = this; | const self = this; | ||||
this.start(); | this.start(); | ||||
const rand = Math.random(); | const rand = Math.random(); | ||||
const test_collection_name = "_test"; | const test_collection_name = "_test"; | ||||
return Promise.resolve() | return Promise.resolve() | ||||
.then(function() { | .then(() => { | ||||
// .insert method should respond with the created document | // .insert method should respond with the created document | ||||
const to_insert = { | const to_insert = { | ||||
value: 1, | value: 1, | ||||
random: rand, | random: rand, | ||||
}; | }; | ||||
return self | return self | ||||
.insert(test_collection_name, to_insert) | .insert(test_collection_name, to_insert) | ||||
.then(function(response) { | .then(response => { | ||||
assert.deepEqual( | assert.deepEqual( | ||||
to_insert, | to_insert, | ||||
response, | response, | ||||
".insert method should respond with the created document" | ".insert method should respond with the created document" | ||||
); | ); | ||||
return Promise.resolve(); | return Promise.resolve(); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function() { | .then(() => | ||||
// check if find resolves with an array | // check if find resolves with an array | ||||
self.find(test_collection_name, {}, {}).then(documents => { | |||||
return self | |||||
.find(test_collection_name, {}, {}) | |||||
.then(function(documents) { | |||||
assert( | assert( | ||||
documents instanceof Array, | documents instanceof Array, | ||||
`datastore.${ | `datastore.${self.name}.find should resolve with an array` | ||||
self.name | |||||
}.find should resolve with an array` | |||||
); | ); | ||||
return Promise.resolve(); | return Promise.resolve(); | ||||
}); | |||||
}) | }) | ||||
.then(function() { | ) | ||||
.then(() => { | |||||
// check if amount of created documents checks out | // check if amount of created documents checks out | ||||
const creates = [ | const creates = [ | ||||
self.insert(test_collection_name, { | self.insert(test_collection_name, { | ||||
value: 2, | value: 2, | ||||
random: rand, | random: rand, | ||||
}), | }), | ||||
self.insert(test_collection_name, { | self.insert(test_collection_name, { | ||||
value: 3, | value: 3, | ||||
random: rand, | random: rand, | ||||
}), | }), | ||||
self.insert(test_collection_name, { | self.insert(test_collection_name, { | ||||
value: 4, | value: 4, | ||||
random: -rand, | random: -rand, | ||||
}), | }), | ||||
]; | ]; | ||||
const created_so_far = 4; | const created_so_far = 4; | ||||
return Promise.all(creates) | return Promise.all(creates) | ||||
.then(function() { | .then(() => self.find(test_collection_name, {}, {})) | ||||
return self.find(test_collection_name, {}, {}); | .then(documents => { | ||||
}) | |||||
.then(function(documents) { | |||||
assert( | assert( | ||||
documents.length === created_so_far, | documents.length === created_so_far, | ||||
`Inserted ${created_so_far} documents so far, but ${ | `Inserted ${created_so_far} documents so far, but ${ | ||||
documents.length | documents.length | ||||
} were returned on .find()` | } were returned on .find()` | ||||
); | ); | ||||
return Promise.resolve(created_so_far); | return Promise.resolve(created_so_far); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(created_so_far) { | .then(created_so_far => { | ||||
// check if there is a proper amount of documents with random value set to rand | // check if there is a proper amount of documents with random value set to rand | ||||
const documents_with_rand = created_so_far - 1; | const documents_with_rand = created_so_far - 1; | ||||
return self | return self | ||||
.find( | .find( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
random: rand, | random: rand, | ||||
}, | }, | ||||
{} | {} | ||||
) | ) | ||||
.then(function(documents) { | .then(documents => { | ||||
assert( | assert( | ||||
documents.length === documents_with_rand, | documents.length === documents_with_rand, | ||||
`Inserted ${documents_with_rand} documents with "random" set to "${rand}" so far, but ${ | `Inserted ${documents_with_rand} documents with "random" set to "${rand}" so far, but ${ | ||||
documents.length | documents.length | ||||
} were returned on .find({random: ${rand}})` | } were returned on .find({random: ${rand}})` | ||||
); | ); | ||||
return Promise.resolve(); | return Promise.resolve(); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function() { | .then(() => { | ||||
// Should store a complex object | // Should store a complex object | ||||
const complex_object = { | const complex_object = { | ||||
id: "aseoifaoeina", | id: "aseoifaoeina", | ||||
body: { | body: { | ||||
name: "Anna", | name: "Anna", | ||||
surname: "Fontanna", | surname: "Fontanna", | ||||
}, | }, | ||||
}; | }; | ||||
return self | return self | ||||
.insert(test_collection_name, complex_object) | .insert(test_collection_name, complex_object) | ||||
.then(function(response) { | .then(response => { | ||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
response, | response, | ||||
".insert with complex object should resolve with that complex object." | ".insert with complex object should resolve with that complex object." | ||||
); | ); | ||||
return self.find(test_collection_name, { | return self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(response) { | .then(response => { | ||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
response[0], | response[0], | ||||
".insert with complex object should store that complex object." | ".insert with complex object should store that complex object." | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => { | ||||
// Should handle dot-notation nested queries | // Should handle dot-notation nested queries | ||||
return self | return self | ||||
.find(test_collection_name, { | .find(test_collection_name, { | ||||
name: complex_object.name, | name: complex_object.name, | ||||
}) | }) | ||||
.then(function(response) { | .then(response => { | ||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
response[0], | response[0], | ||||
".find method should handle dot notation queries" | ".find method should handle dot notation queries" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => | ||||
return self | self | ||||
.find(test_collection_name, { | .find(test_collection_name, { | ||||
body: { | body: { | ||||
name: complex_object.name, | name: complex_object.name, | ||||
}, | }, | ||||
}) | }) | ||||
.then(function(response) { | .then(response => { | ||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
response[0], | response[0], | ||||
".find method should handle nested object queries" | ".find method should handle nested object queries" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | |||||
}) | }) | ||||
.then(function(complex_object) { | ) | ||||
.then(complex_object => { | |||||
// .update should modify document values with dot notation | // .update should modify document values with dot notation | ||||
complex_object.name = "Hanna"; | complex_object.name = "Hanna"; | ||||
return self | return self | ||||
.update( | .update( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}, | }, | ||||
{ | { | ||||
name: complex_object.name, | name: complex_object.name, | ||||
} | } | ||||
) | ) | ||||
.then(function() { | .then(() => | ||||
return self.find(test_collection_name, { | self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | |||||
}) | }) | ||||
.then(function(results) { | ) | ||||
.then(results => { | |||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
results[0], | results[0], | ||||
".update should modify document values with dot notation" | ".update should modify document values with dot notation" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => { | ||||
// .update should modify document values using nested object as a query | // .update should modify document values using nested object as a query | ||||
complex_object.name = "Marzanna"; | complex_object.name = "Marzanna"; | ||||
return self | return self | ||||
.update( | .update( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}, | }, | ||||
{ | { | ||||
body: { | body: { | ||||
name: complex_object.name, | name: complex_object.name, | ||||
}, | }, | ||||
} | } | ||||
) | ) | ||||
.then(function() { | .then(() => | ||||
return self.find(test_collection_name, { | self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | |||||
}) | }) | ||||
.then(function(results) { | ) | ||||
.then(results => { | |||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
results[0], | results[0], | ||||
".update should modify document values using nested object as a query " | ".update should modify document values using nested object as a query " | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => { | ||||
// .update should insert new value to a field that previously had no value (undefined) | // .update should insert new value to a field that previously had no value (undefined) | ||||
complex_object.other = "Focca"; | complex_object.other = "Focca"; | ||||
return self | return self | ||||
.update( | .update( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}, | }, | ||||
{ | { | ||||
body: { | body: { | ||||
other: complex_object.other, | other: complex_object.other, | ||||
}, | }, | ||||
} | } | ||||
) | ) | ||||
.then(function() { | .then(() => | ||||
return self.find(test_collection_name, { | self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | |||||
}) | }) | ||||
.then(function(results) { | ) | ||||
.then(results => { | |||||
assert.deepEqual( | assert.deepEqual( | ||||
complex_object, | complex_object, | ||||
results[0], | results[0], | ||||
".update should insert new value to a field that previously had no value (undefined)" | ".update should insert new value to a field that previously had no value (undefined)" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => { | ||||
// .remove should remove only one document when "just_one" is set to true | // .remove should remove only one document when "just_one" is set to true | ||||
return Promise.all([ | return Promise.all([ | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
]) | ]) | ||||
.then(function() { | .then(() => | ||||
// all the "complex_object" documents have the same id | // all the "complex_object" documents have the same id | ||||
return self.remove( | self.remove( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}, | }, | ||||
true | true | ||||
); | ) | ||||
}) | ) | ||||
.then(function() { | .then(() => | ||||
return self.find(test_collection_name, { | self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | |||||
}) | }) | ||||
.then(function(results) { | ) | ||||
.then(results => { | |||||
assert( | assert( | ||||
results.length === 3, | results.length === 3, | ||||
".remove should remove only *one* document when `just_one` argument is set to true" | ".remove should remove only *one* document when `just_one` argument is set to true" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function(complex_object) { | .then(complex_object => { | ||||
// .remove should remove all matching documents when "just_one" is falsy | // .remove should remove all matching documents when "just_one" is falsy | ||||
return Promise.all([ | return Promise.all([ | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
self.insert(test_collection_name, complex_object), | self.insert(test_collection_name, complex_object), | ||||
]) | ]) | ||||
.then(function() { | .then(() => | ||||
// all the "complex_object" documents have the same id | // all the "complex_object" documents have the same id | ||||
return self.remove( | self.remove( | ||||
test_collection_name, | test_collection_name, | ||||
{ | { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}, | }, | ||||
false | false | ||||
); | ) | ||||
}) | ) | ||||
.then(function() { | .then(() => | ||||
return self.find(test_collection_name, { | self.find(test_collection_name, { | ||||
id: complex_object.id, | id: complex_object.id, | ||||
}); | |||||
}) | }) | ||||
.then(function(results) { | ) | ||||
.then(results => { | |||||
assert( | assert( | ||||
results.length === 0, | results.length === 0, | ||||
".remove should remove all matching documents when 'just_one' is falsy" | ".remove should remove all matching documents when 'just_one' is falsy" | ||||
); | ); | ||||
return Promise.resolve(complex_object); | return Promise.resolve(complex_object); | ||||
}); | }); | ||||
}) | }) | ||||
.then(function() { | .then(() => { | ||||
self.clear_collection(test_collection_name); | self.clear_collection(test_collection_name); | ||||
}) | }) | ||||
.catch(function() { | .catch(() => { | ||||
self.clear_collection(test_collection_name); | self.clear_collection(test_collection_name); | ||||
return Promise.reject("Compatibility test unsuccesfull"); | return Promise.reject("Compatibility test unsuccesfull"); | ||||
}); | }); | ||||
}; | }; | ||||
module.exports = Datastore; | module.exports = Datastore; |