DB/Text trace log format method

by Peter Tyrrell Tuesday, August 05, 2008 11:15 PM

Further to my post of May 2007, where I described how to create a trace log in DB/Text and handle exceptions, here is a method that is handy for building more complex log statements.

   1: // construct formatted log statement
   2: function logFormat(val, arg1, arg2, arg3)
   3: {
   4:     var formattedVal = val;
   5:     if (arg1 != null)    {
   6:         formattedVal = formattedVal.replace("{0}", arg1);
   7:     }
   8:     if (arg2 != null) {
   9:         formattedVal = formattedVal.replace("{1}", arg2);
  10:     }
  11:     if (arg3 != null) {
  12:         formattedVal = formattedVal.replace("{2}", arg3);
  13:     }
  14:     log(formattedVal);
  15: }
  16:  
  17: // write log statement to form box
  18: function log(val)
  19: {
  20:     var box = Form.boxes("boxDebugLog");
  21:     if (box == null)
  22:         return;    
  23:     
  24:     if (box.content != '')
  25:     {
  26:         box.content += "\n";    
  27:     }    
  28:     box.content += val;
  29: }

Overview

logFormat takes a string value and up to 3 arguments, and replaces tokens found in the string value with those arguments. It's based on C#'s string.Format method, and others like it.

Example

It's easier to read (and write) a format string that contains tokens than a string concatenated together with plus signs.

   1: var count = 10;
   2: var name = "Peter";
   3: var duration = 30;
   4:  
   5: function LogTheOldWay()
   6: {
   7:     log(name + " was lashed with a wet noodle " + count + " times for " + duration + " seconds.");
   8: }
   9:  
  10: function LogTheNewWay()
  11: {    
  12:     logFormat("{0} was lashed with a wet noodle {1} times for {2} seconds.", name, count, duration);
  13: }

Update

My example above only proves how piddly my skills really are. There's a *much* better way of doing this that allows for n arguments instead of a maximum of three. I had forgotten that every javascript function has a local property called arguments that contains all parameters passed to the function as an array.

   1: function logFormat(val)
   2: {
   3:     var formattedVal = val;
   4:   for(i = 1; i < arguments.length; i++)
   5:   {
   6:     formattedVal = formattedVal.replace("{" + (i - 1) + "}", arguments[i]);
   7:   }
   8:   return formattedVal;
   9: }

"Static" properties in javascript. Kinda.

by Peter Tyrrell Tuesday, August 05, 2008 10:55 PM

The following gives me the ability to access javascript properties in a static kind of way. Not really, since the object has been instantiated, but at least I don't have to define a specific object, then call its constructor all the time to new it up and get at its properties.

   1: // declare globally
   2: var Artist = {
   3:     Fields: {
   4:         Id: "ID",
   5:         FullName: "Term",
   6:         FirstName: "First Name",
   7:         LastName: "Last Name",
   8:         Birth: "Date of Birth",
   9:         Death: "Date of Death"
  10:     }
  11: };

Overview

I like to store DB/Text field names in this way, as they become (pseudo) strongly-typed and the magic strings are stored in one place only, instead of scattered across my code like dandelion seeds.

It can be difficult to work in javascript after C# and other full-featured languages. This is the closest I could come to static properties or a struct. If I weren't scripting in DB/Text, a proprietary closed system, I would be using jQuery or mootools, which put the joy back in joyvascript.

Example

Now I can access field names statically as follows. Look ma, no constructors!

   1: function SomeMethod()
   2: {
   3:     var idFieldName = Artist.Fields.Id;
   4: }

A highly reusable recordset script for DB/Text

by Peter Tyrrell Tuesday, August 05, 2008 10:26 PM

This javascript function performs a search against a DB/Text database and returns a sorted array of dictionary objects with fieldnames as keys.

Parameters

Search(commandQuery, textbase, password, fieldsToReturn, sortFields)

commandQuery (string): A query in command syntax.
textbase (string): The name of the textbase to query.
password (string): A textbase password that allows querying.
fieldsToReturn (array): An array of field names whose values the query will retrieve from result records.
sortFields (array): An array of field names to sort the recordset by.

Dependencies

SortByField(recordset, sortFields): A method that sorts a recordset by the fields provided.

   1: // returns array of dictionaries with fieldsToReturn as keys
   2: function Search(commandQuery, textbase, password, fieldsToReturn, sortFields)
   3: {
   4:     var rs;
   5:     var output = [];
   6:     
   7:     rs = Application.newRecordset(textbase, Application.activeTextbase.path, password);
   8:     if (rs != null)
   9:     {
  10:         try {
  11:             rs.Open(commandQuery);
  12:             if (rs.Errors.Count > 0)
  13:             {
  14:                     // log error
  15:             }
  16:             else if (rs.RecordCount > 0)
  17:             {
  18:                 // sort the recordset
  19:                 rs = SortByField(rs, sortFields);
  20:                 
  21:                 rs.MoveFirst();
  22:                 while (!rs.EOF)
  23:                 {                    
  24:                     // create dictionary of field values, add to output list
  25:                     var record = new Object();
  26:                     for (var i = 0;i < fieldsToReturn.length;i++)
  27:                     {
  28:                         record[fieldsToReturn[i]] = rs.Fields(fieldsToReturn[i]).Value;
  29:                     }
  30:                     output[output.length] = record;
  31:                     
  32:                     rs.MoveNext();                    
  33:                 }
  34:             }    
  35:         }
  36:         catch (e) {
  37:             // log exception
  38:         }
  39:         finally 
  40:         {
  41:             rs.Close();    
  42:         }
  43:     }
  44:     return output;
  45: }
  46:  
  47: // returns recordset sorted by fields provided
  48: function SortByField(recordset, sortFields)
  49: {
  50:     var sort = recordset.NewSortDescriptor();
  51:     for (var i = 0;i < sortFields.length;i++)
  52:     {
  53:         if (i >= (sort.MaxSORTFIELDS - 1))
  54:         {
  55:             break;    
  56:         }
  57:         sort.sortFieldName(i) = sortFields[i];
  58:     }
  59:     recordset.Sort(sort);    
  60:     return recordset;
  61: }

Overview

The main advantage of this function is its agnosticism towards the fields it is to retrieve. It relies on the fact that objects in javascript inherently behave as associative arrays, e.g.

var myObject = new Object();
myObject["myKey"] = "some value";

For each record in the query's result set, an object is created with fieldsToReturn as keys, and the function's return type is simply an array of these objects. The fact that I am using these objects solely for their key/value behaviour leads me to refer to them as dictionaries. They are not dictionaries in the sense of specialized collections as with other languages outside of javascript.

Example

The following is a simplified method that I would never use in production code. It grabs search text from a box, creates a command query, then searches the Catalog. The result set will be sorted by Title, and will contain values from Title and Author fields. It then shows an alert message with the title from the first result in the set.

Note that field values are retrieved by using field names as keys on the objects in the results array.

   1: function btnSearch_onClick()
   2: {
   3:     var searchText = Form.boxes("boxSearchText").content;
   4:     var query = "find (Title ct {0}) or (Author ct {0})".replace("{0}", searchText);
   5:     var results = Search(query, "Catalog", "password", ["Title", "Author"], ["Title"]);
   6:     
   7:     var msg = "First result Title is '{0}'".replace("{0}", results[0]["Title"];
   8:     Application.message(msg);
   9: }

Inmagic DB/TextWorks and Vista Virtualization

by Denise Bonin Monday, July 07, 2008 5:10 PM

This post is a follow-up to Peter's post Inmagic WebPublisher PRO and Vista Virtualization, but specifically pertaining to DB/TextWorks. 

I recently had a client who created and added a bunch of records to a new textbase located in a folder under Program Files on her Vista-installed laptop.  When it came time to move the textbase off her laptop onto another computer she zipped up all the textbase files, copied the zip file to her thumb drive and prepared to unzip the files onto the other machine.  With files unzipped on the other machine (an older XP-installed desktop computer), she enthusiastically went to show off her newly created and populated textbase. 

Much to her surprise DB/TextWorks produced a disheartening message indicating that the textbase was empty.  How could this be, she had 170 records in the textbase when it was on her laptop and she had copied every textbase file from the correct folder on her laptop.  I got involved and we looked this way and that way - on both machines - and there was nothing that we could see that could indicate that the textbase could possibly be empty (the .btx, .dbt and .occ files were rather large).

The ah ha moment came when Kathy suggested that Peter had posted something about this on our Blog - back in March 2008 (see above link).  I had skipped over that posting because it had referenced WebPublisher, but in fact it told me exactly what I needed to know.  To change the text and code slightly from what Peter posted:

For instance, say DB/TextWorks indicates that a textbase is located at:

%Program Files%\Inmagic\Textbases

Vista detects that DB/TextWorks does not have permission to save to that location and copies the file to:

%Users%\<your account>\AppData\Local\VirtualStore\Program Files\Inmagic\Textbases

Subsequent read/write operations access the VirtualStore version of the file, even though DB/TextWorks will still think it is accessing the Program Files directory. Poor deluded DB/TextWorks.

It took about 1 minute to find the database files in the VirtualStore location - thank you Peter! - however, there was more, or in this case less, to come!  Two of the essential files were missing.  They were the .tba file and the .sdo file.  Why those two? Who knows?  However, combining the new found files (.acf, .btx, .dbo, .dbr, .ixl, .log, and .occ)  from the VirtualStore location with the .tba and the .sdo file from the presumed location – under Program files, allowed us to complete the textbase and transfer it to another location. 

The lesson learned here:

  • On a Vista machine DO NOT install textbases under Program files. 

And a Note: 

  • this problem only occurs with Vista's UAC (user account control) turned on.

DB/TextWorks 11.0 Service Pack 1 now available

by Administrator Monday, May 26, 2008 9:50 PM

Inmagic, Inc. have announced that a service pack is now available for DB/TextWorks version 11.

This service pack includes fixes for the following issues.

  • Substitution lists where the code to the left of the colon is a single character do not perform the substitution
  • Several issues with Export Query Screen to HTML and Export Editing Form to HTML
  • A few issues with the HTML Preview feature in the Query Screen Designer
  • Added HTML Preview to available toolbar buttons for Query Screen Designer
  • Form Designer: addressed issue with "Large buttons on toolbars" option

The Service pack can be downloaded from the Inmagic Customer extranet at http://support.inmagic.com/downloads/extranet-files/service_packs.html

Month List