After I wrote my previous post on handling script errors, it occurred to me I had taken knowledge about about tracing and exceptions for granted. So, here is a description of how I add a trace log and exception handling to my scripts in DB/ or CS/Textworks.
Make an Inmagic DB/Textworks Trace Log
First, add a form box and two buttons to the form, named boxDebugLog, btnBugs, and btnClearLog.
Add code to handle the two buttons and and a log method, which writes a new line into the form box whenever called. The bugs button ensures there is no syntax error lurking in the code, which would halt any code from running on the form, and therefore would stop "no syntax bugs" from being written into the log (no news is bad news). The isLogging boolean variable can be turned on and off globally so that trace statements don't have to be ripped out of deployed code.
log("no syntax bugs");
Form.boxes("boxDebugLog").content = '';
var box = Form.boxes("boxDebugLog");
if (box.content != '')
box.content += "\n";
box.content += val;
Within the code, insert trace statements wherever you want to see the results of an operation.
log("GetRequestorsByQuery() " + commandQuery);
The result of the above would look like this in the Debug Log form box:
Extend the Trace Log to Handle Exceptions
The above is good for viewing the results of expected steps in a series of operations and can help you debug. Of course, when you work with code the real bugbear is the unexpected. And, further, there are operational errors (not bugs) which may crop up long after you're done building the code.
Inmagic DB/Textworks presents us with an obstacle in that any error encountered simply halts the process and does not in any way indicate there has been an error. To the average user this is perhaps a blessing (ignorance being bliss), but to the developer it is nothing but an impediment. Fortunately there is a way to free the errors from their airless dungeon so as to inform you of what is really going on.
The try/catch/finally statement attempts operations with instructions (the catch block) on what to do if an exception is encountered in the try block. The finally block tells what to do after try and catch have been dealt with, and is useful for closing objects or releasing resources that might otherwise have been stuck as a result of the exception encountered.
In our case, we can use try/catch to handle exceptions, and log the error messages to the trace log.
var item = new catalogItem();
var isInserted = false;
isInserted = InsertCatalogRecord(item);
log("Unable to add to catalog. " + err.name + ": " + err.message);
You can also generate custom exceptions using the throw statement.
throw new Error("something went wrong");
throw "something went wrong";
So the throw statement allows you to "throw" (i.e. raise) an error whenever you like. Why would you want to, if the whole point of this exercise is to eliminate errors from the script? The reason becomes clear when you are working with operations whose scope is beyond your immediate control. In the scenario above where try/catch is demonstrated, we are adding a new record to a catalog. It's possible the catalog might not be there, or might reject a new record for some reason, or a field name changed since we wrote the script. If any of these happens, or anything else we can't now predict, we can still catch the problem and deal with it in a predictable way so that the script fails gracefully and passes on vital information before it expires.
If you wanted to force the Inmagic recordset object to throw any error it encountered, you could do that, for instance (and I do).
if (rs.Errors.Count > 0)
throw new Error(rs.Errors(0).Description);
It takes a bit of an adjustment at first to deliberately throw an error, or to let an error bubble up to another, calling function and deal with it there, but it is a powerful and freeing concept once you get it.