2. The ColdFusion Data Model
- John Willis
Structures
CF structures are very similar to JavaScript structures, in that they can be declared as follows using object-literal notation:
var myStruct = {key: "value1", key2: "value2"};
Structure members can then be accessed like this:
var myValue = myStruct.key; /* "dot" notation */ var myValue = myStruct["key"]; /* "array" notation */ var myKey = "key"; var myValue = myStruct[myKey]; /* indirection through "myKey" variable */
Much like MUMPS, CF structures can pop into existence simply by having values assigned to them:
var myStruct["key1"]["key2"] = "value"; /* this is just like SET myStruct("key1","key2")="value" in MUMPS */
We can test for the existence of a key like this:
if(structKeyExists(myStruct, "key")) { writeOutput("The key 'key' exists in 'myStruct'!"); }
The primary difference between CF structures and MUMPS trees is that CF structures are not automatically sorted into any particular collating order: because CF structures are internally implemented as hashes, keys are stored in the order in which they are inserted.
Mapping MUMPS Globals to CF Structures
One of the most interesting and compelling features of the MUMPS database is that a global node can contain both data and child subscripts. Consider the code snippet below:
SET ^myGlobal(1)="value1" SET ^myGlobal(1,2)="value2"
^myGlobal(1) contains both data (value1) and child subscripts (2). However, what would seem like the equivalent CF code will not work:
var myGlobal[1] = "value1"; myGlobal[1][2] = "value2";
If you attempt to do this, the CF engine will throw an exception on the second line. So, how does CFMumps claim to seamlessly handle MUMPS global nodes containing both data and child subscripts? It's really quite simple: CFMumps makes use of a property of ANSI-standard MUMPS, which is that null subscripts are not allowed. The following, therefore, is illegal in standard MUMPS:
SET ^myGlobal(1,"",3)="value1"
So, given what we know about the MUMPS rules, we can quite safely assume that no valid MUMPS data will contain a subscript that is an empty string. However, empty structure keys are perfectly valid in CF structures:
var myGlobal[1][""] = "value1"; myGlobal[1][2] = "value2";
The above CF code will work perfectly, and if the myGlobal CF structure is passed to the CFML function serializeJSON(), it will produce a valid JSON representation fully conforming to David Wicksell's JSON-M standard, which makes use of the same property of JSON. In fact, it was JSON-M that inspired this solution in CFMumps.
What About GT.M?
FIS GT.M includes a rarely-used feature whereby null subscripts may be enabled for any given database region. Using this feature with CFMumps is not supported, and will cause data loss. Coherent Logic Development is not responsible for any data loss resulting from the enabling of null subscripts in GT.M.
ColdFusion Components
The CFML programming language provides object-oriented programming facilities by way of CF Components, commonly referred to as CFCs. Each CFC is conceptually similar to a class in other OO languages, which means that a CFC encapsulates both data and code. Data members of CFCs are referred to as properties, while the code to interact with those properties are methods. All CFC methods are actually functions (similar to extrinsic functions in MUMPS) which gain the benefits of the properties exposed in their containing CFC. In the case of CFMumps, each API is a CFC whose properties define and maintain the state of the MUMPS database connection, and whose methods are the APIs against which your applications will be developed, such as get(), set(), kill(), data(), and order().
You can think of each CFC as a complex, high-level data type that just happens to also contain code that you can run.
In order to gain access to the methods and properties of the CFCs which implement the CFMumps API, you need to create an instance of the appropriate CFC. An instance is simply a variable through which you access the methods and properties of the API you wish to use. Creating an instance is accomplished with the createObject() CFML/CFScript function.
Here is an example–expressed in both CFScript and tag-based CFML--creating an instance of the basic API:
var myCFCInstance = new lib.cfmumps.Mumps();
<cfset var myCFCInstance = new lib.cfmumps.Mumps()>
Each of the above code snippets will produce identical results: the variable myCFCInstance is created and initialized as an instance of lib.cfmumps.mumps, which is the component that implements the CFMumps basic API. Its methods are available by appending a dot to the variable name myCFCInstance, followed by the name of the method you wish to call, as follows:
myCFCInstance.open();
<cfset myCFCInstance.open()>
The above examples open the database for the myCFCInstance instance of the lib.cfmumps.Mumps CFC.