Im just new to knex and came across Transactions. I think it's useful to use since it has a rollback feature. Tried using it (see code below)
await knex.transaction(trx => {
knex.raw(delete from myTable where "id" = 1 )
.transacting(trx)
.then(trx.commit)
.catch(trx.rollback)
})
I just wanted to delete a row with a certain id nothing more and less.
Works fine, then i tried to remove 'trx.commit'. I was expecting that it wont apply the query but it did. From what I understand, if trx.commit is not called the query will not run and wont affect the database.
Is my understanding wrong? Did I use knex.raw improperly inside knex.transactions? I dont see examples of transactions that uses raw queries. I am connected to a database in my localhost(postgresql) btw.
knex.js has a modified promise interface.
Calling .then triggers the query to actually fire (including the BEGIN transaction if it is the first query). Note that in a single knex query you won't need to call rollback since a single query to the database should be transactional and abort/rollback if any errors are encountered.
Based on your usage (and the docs) if you remove trx.commit it should not commit at all. I recommend actually returning a promise to the transaction callback - then it will auto-commit on promise resolution, and auto-rollback on promise failure.
In the following usage if either query failed it would auto-rollback everything.
knex.transaction(trx => {
return Promise.all([
knex.raw(`update table x`).transacting(trx),
knex.raw(`update table y`).transacting(trx)
]);
})
This is my code:
var pushRef = currentAssignment.child('answers').push().catch(e => console.log('push', e));
pushRef.set({
// downloadURL: downURL,
textAnswer: textAnswer,
date: this.generateDate(),
seen: false,
// firebaseKey: pushRef.getKey(),
workKey: this.props.questionId
})
When I try to run it, I get this error: pushRef.set(), but according to this part of the documentation it looks to me like I'm doing everything the same way. Here's Google's example of push instruction:
var postsRef = ref.child("posts");
var newPostRef = postsRef.push();
newPostRef
.set({
author: "gracehop",
title: "Announcing COBOL, a New Programming Language"
});
// we can also chain the two calls together
postsRef
.push()
.set({
author: "alanisawesome",
title: "The Turing Machine"
});
So what am I missing?
By adding .catch(e => console.log('push', e)) behind push() you change it from a firebase database reference to something else. So removing that will fix this.
As far as I know calling push() (without parameters) will never generate an error, it simply generates a firebase reference (unique key) client side.
Your code is expecting that catch() returns a database reference. It doesn't - catch() always returns a promise.
The use of catch here is unnecessary because push() with no arguments is a completely local operation. It returns a database reference that can also be used like a promise (a ThenableReference).
If there is any error to possibly catch here, it's on the promise returned by set(). That call will fail if security rules are violated during the write operation.
I'm running into problems with the validated method package in my app tests. I'm calling my methods through the _execute function in order to be able to pass a userId to simulate a logged-in user while testing. The problem is that my asserts right underneath that _execute are called before the method has a chance of completing. I know my test works though because it only happens sometimes, mostly because mongo isn't always returning results quite as fast.
I looked around and found a todos app that uses the _execute function in its tests. I can't get those tests to fail no matter how many times I rerun them, though.
This is an example of my test code.
describe('clients.add', function() {
it('should add an empty (draft) client', function() {
const res = clients_add._execute({ userId: 'CURRENTUSERID' }, { company_id: c1._id });
assert.instanceOf(res, Mongo.ObjectID, 'method returns the newly created clients ID');
const db_client = Clients.findOne(res);
assert.isTrue(db_client.draft, 'client is drafted');
assert.isDefined(db_client.created, 'there\'s a created date');
});
});
clients_add does quite a few permission checks and can therefor take a little while before completing. Rerunning this test 20 times will fail about 5 times and pass the other 15.
Shouldn't the _execute function be synchronous? How do I make it? What am I missing?
In server code, if you provide a callback to database modification functions like insert, it returns the created ID instantaneously, and runs the callback only once the database has acknowledged the write. If you don't provide a callback, the insert call is synchronous and throws an error if the operation fails. See more about this in Meteor docs.
It seems that you have provided an error-handling callback to the insert-function in your method code. This causes the inconsistent behavior, since the database might not actually have had time to do the write before you call findOne in your test. Also, this is redundant since if an error occurs in the insert, the method has already returned and the error is never shown to the user. It's better to simply omit the error-handling callback altogether:
return Clients.insert(new_client);
Previous post: Parse .then method and chaining | Syntax eludes me
My original question was well answered by Nath. However I'm currently experiencing a TypeError which I am yet unable to resolve.
TypeError message:
TypeError: e is undefined
...arse.Object");return{__type:"Pointer",className:this.className,obj
My current code (updated 2014-08-14 18:44):
function harness(){
try{
console.log("harness function");
Parse.initialize("*key1*", "*key2*"); //Note: I do have the keys set properly
var query = new Parse.Query("Users");
var userEmail = app.getValue("txtEmail");
console.log("userEmail: "+userEmail);
//Note: Using Application Craft hence the use of 'app.getValue' and other custom JS functions
query.equalTo("email", userEmail); console.log(query);
query.find().then(
function(results) {
console.log("Within the Then!");
console.log(results);
return query.find();
},
function(error){
console.log("Could be an error"+error);
return;
}
);
console.log("END harness function");
}
catch(err){
errorHandler("harness ERROR", err.message);
console.log(err);
}
}
Having read various forum posts I've investigated the stack trace and given the variable 'e' am fairly certain it's the ParseCDN I'm not calling correctly. I suspect my inexperience with returning promises is the source of the issue (tried to follow Nath's advice). The commented code block at the top was one of my variations of a promise to be returned; having read through the Parse API Docs it seemed that .then inherently returned a promise anyway so 'settled' on simply returning my results, and then the queryObject again (per their samples).
The DOM upon error is interesting because it lists find(e) as a method, yet not then(). Not sure if I'm referring to an outdated js library perhaps (don't think so).
If anyone can assist, or potentially expand upon Nath's work so far (copy below) I would greatly appreciate it.
Many thanks
-James
Amended code snippet from Nath
query.find().then(function(result){
doSomethingAsync(); //must return a promise for chaining to work!
}).then(null,function(error){
// an alternative way to handle errors
//handles errors for all chained promises.
})
So, I'm completely new to mocha, and promises and I was asked to write integration tests, which posts form data to a page, gets an authentication key, and then run tests on the key.
I'm getting the key back properly, which is confirmed by my log statement, but when I run mocha, my test says 0 passing. It doesn't even print out the descriptions for the 'describe' and 'it' statements, implying that they do not work within the promise. Is there away that I can this work, while still giving the assertions access to my authorization key?
require('should');
require('sails');
var Promise = require("promise");
var request = require('request');
describe('Domain Model', function(){
var options = { url:'link',
form:{
username: 'xxxxx#xxxxxx',
password: '0000'
},
timeout: 2000
};
//request auth key
var promise = new Promise(function(resolve,reject){
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
resolve(body);
});
});
//this is where I'm getting lost
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
describe('Initialize',function(){
it('should be an string', function(){
(token).should.be.type('string');
});
});
});
});
Mocha is not able to find your tests because you're not structuring them correctly. The it() blocks should go immediately within the describe() blocks (and the describe() blocks may be nested within each other as you see fit). If you want to use promises, the promises should go inside the it() blocks, not the other way around. So, as a first pass, the updated code should look something like this (I'm cutting some parts out for brevity):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
});
});
});
});
Note that the promise is now contained inside the body of the it(). Mocha should now be able to find your test. However, it won't pass. Why not?
As you probably know, promises are asynchronous. Testing asynchronous code using mocha requires using the done callback - see the guide for more info. Basically, this means the it() block should accept a parameter named done (the name is important!). This done thingy is something that mocha passes in automatically - its presence indicates to mocha that this test contains asynchronous code, and that therefore it has not completed executing until you say so. The way you indicate that your test is done is by executing done, because done is in fact a callback function. You should execute done() at whatever point your test is deemed complete - i.e., at the end of whatever code block is supposed to run last, which in your case is the bottom of the .then() handler for the promise. So, improving upon our last version, the code now looks like this (again, cutting some parts for brevity):
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data,test){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Note that I just added the done parameter to it(), and then I called it at the bottom of the then().
At this point, the code should work, I think... I'm not sure as I'm not able to test it. However, there are a couple more things we could do to improve upon this further.
First, I question your use of promises here. If you had an API for obtaining the access token, then I would opt to have that API return a promise because promises are very convenient for the caller. However, as I'm sure you've noticed, constructing promises can be a bit tedious, and I don't think it adds much value for your code. I would opt to just do this:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
request.post(options, function(error, response, body){
//body contains the auth key, within a string of JSON
var token = (JSON.parse(body))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Isn't that so much shorter and sweeter? The code is still asynchronous, so you should still make sure your it() block accepts a done callback, and you should call it when your test has finished.
Now, if you still insist on using promises, then there's one more thing I have to warn you about. What happens if there's an error inside of your .then() handler code? Well, according to the documentation:
If the handler that is called throws an exception then the promise
returned by .then is rejected with that exception.
Do you have a rejection handler for your promise? No. So what does that mean? That means the error will get swallowed up silently. Your test will fail with Error: timeout of 2000ms exceeded, which is because the done handler never got called, but the actual cause of the error won't be shown, and you'll be pulling your hair out trying to figure out what went wrong.
So what can you do? You could use the second parameter to .then() to specify a rejection handler, and in there, you could take advantage of the fact that the done callback that mocha passes in to your test accepts an error argument, so if you call done("something"), your test will fail (which is what we want in this case), and the "something" will be the reason. So here's what that will look like in your case:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.then(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
}, function (err) {
done(err);
});
});
});
});
However, we can do even better. Consider what happens if an error gets thrown from within the rejection handler. Not likely, since you're not doing a whole lot in there - just calling done(err). But what if it does happen? Well, pretty much the same thing - the error will get silently swallowed up, the test will fail with a non-specific timeout error, and you'll be pulling out your hair again. Is there a way we can get that error to bubble up and get rethrown?
As a matter of fact, there is: Both Q and the promise library that you're using have an alternate handler called .done() (not to be confused with mocha's done callback). It's similar to .then(), but with a slightly different behavior around uncaught exceptions. From the documentation:
Promise#done(onFulfilled, onRejected)
The same semantics as .then except that it does not return a promise
and any exceptions are re-thrown so that they can be logged (crashing
the application in non-browser environments)
Perfect, that's exactly what we want. Just be sure to understand when you should use .then(), vs when you should use .done(). The Q API does a fantastic job of explaining (and the promise library you're using has similar behavior - I tested):
The Golden Rule of done vs. then usage is: either return your promise
to someone else, or if the chain ends with you, call done to terminate
it. Terminating with catch is not sufficient because the catch handler
may itself throw an error.
(Note: .catch() appears to be Q-specific, but it's pretty similar to the onRejected callback, which is the second parameter to .then().).
So with that in mind, just replace your last .then() with a .done(). When you use .done(), you can just omit the rejection handler and rely on the promise library to re-throw any unhandled expections, so you will get an error description and a stack trace. With the above in mind, your code now looks like:
describe('Domain Model', function(){
var options = { ... };
describe('Initialize',function(){
it('should be an string', function(done){
//request auth key
var promise = new Promise(function(resolve,reject){
// ...
});
promise.done(function(data){
var token = (JSON.parse(data))["access_token"];
console.log(token);
(token).should.be.type('string');
done();
});
});
});
});
Basically, ignoring the previous code sample, the only difference from the one before that is we're using .done() instead of .then().
Hopefully, this covers most of what you need to get started. There are other things you might want to consider, like potentially retrieving the auth key inside of a before() hook instead of an it() block (because I'm assuming the real thing you're testing is not the retrieval of the key - that's just a prerequisite to test the things you actually want to test, so a hook might be more appropriate - see here). I also question whether or not you should be connecting to an external system from within your tests at all, versus just stubbing it out (that depends on whether these are unit tests or integration tests). And I'm sure you can come up with a better assertion that just checking that token is a string, like using a regex to make sure it matches a pattern, or actually testing a request for a protected resource and making sure that it goes through. But I'll leave those questions for you to think about.