Tag Archives: Structs

Using CouchDB with Uniface

I won’t repeat any definitions of what NoSQL databases are, nor a review of any specific products. I’ve read plenty about NoSQL databases and I think that the general view of developers is that it is one more tool in the arsenal of application development. I generally believe that you should choose the right tool for the job at hand.

So, you may get that task one day where the advantages of using a NoSQL database outweigh the disadvantages. Can, or how can you use this database with Uniface? The answer definitely depends on the specific NoSQL database product. Between them all, they have a large variation in their APIs and data structures. For that reason I will just describe my experiences doing some prototyping with CouchDB from Apache. Be aware that this is slightly different to Couchbase, which appears to be a commercialised offshoot from what Apache took on board as an open source project. For brevity, I refer you to the website for information about CouchDB’s characteristics:   https://couchdb.apache.org/

The major characteristic of CouchDB is that the documents stored in the database are in JSON format. While investigating another project, I stumbled upon a convenient source of JSON formatted documents that I could use to store in my CouchDB database. I hope that you aren’t offended by simple Chuck Norris jokes. It is a unique genre that not all will enjoy, but it served my purposes adequately. Thus in studying my prototype, you could imagine how you would handle more business related data.

I have provided a sample form in the community samples part of Uniface.info. All you need to do, besides compiling that one form, is to download and install CouchDB from the earlier link provided. I downloaded the Windows version. I manually created the “cnjokes” database using the CouchDB provided Futon utility, also installed with the Couch DB. I also manually defined the design document “vcnjokes”; more about that later.

The top part of the COUCHTEST01 form is really a “utility” area, where you can manually enter URIs and run requests against the “cnjokes” database.   These requests use the UHTTP internal Uniface component. The way the CouchDB API is structured gives you a very RESTful web service interface, though there are some comments on how RESTful CouchDB really is, within their online tutorials. The results of the calls are available in the message frame.   You can press the GET button without adding anything to the URI and you will see some global information about the “cnjokes” database. Overall, this “utility” is not as flexible as the CouchDB provided Futon utility, but it might be helpful during further Uniface development.

The 4 buttons, and accompanying entity and fields provide the real prototype; effectively demonstrating a CRUD lifecycle of managing CouchDB documents. The UHTTP component is used to obtain a CN joke in JSON format from an internet website, and then the UHTTP component is used to interact with the localhost CouchDB server. The document format is deliberately unchanged between the external joke website and CouchDB. However, you could manipulate the JSON before storing it in CouchDB if required, using Structs. Note that I have used $uuid as the basis for assigning a document ID.

The other 3 buttons query the CouchDB database using views. Ad-hoc queries are not possible in CouchDB. The 3 views are defined in a single “design document” called “vcnjokes”. The source for that design document are provided with the sample download, as comments for the COUCHTEST01 form.

  • Button “Get all current jokes from CouchDB” uses view “joke_by_jokeid”. All jokes are retrieved, and sorted by joke_ID, but only a few columns are selected. It cannot be edited as the revision ID is not available. Note that escaped quotation symbols in the data are displayed as quotations.
  • Button “Get all nerdy jokes from CouchDB” uses view “nerdy_joke”. The jokes list is filtered to those that have a category of “nerdy”. This list also cannot be edited.
  • Button “Get all current data from CouchDB for edit” uses view “all”. This view references all of the document and so all fields, including revision ID, are available. Thus editing can be done, and when stored, the new revision number is updated. Note that escaped quotation symbols appear as stored, for ease of updating.

When preparing the JSON for display in a Uniface form, it is certainly necessary to use Structs to manipulate it into the Component data structure. In fact the choice of the external data structure of the form entities is quite arbitrary. CouchDB has no fixed schema. Thus you can never be sure that an external application won’t add data that renders your entities and fields obsolete. All I could do is generate a useful number of jokes, and observe that some of them have one category with a value of “nerdy”. However, I can see that the category is defined as a JSON array, and so I make sure to set   $tags->jsonClass = “array” before converting the struct to a JSON string. This is what led to the one to many relationship between CNJOKE and JCATEGORY. With my CouchDB data set, I verified my schema by manually adding several extra categories to some jokes, using structure editor commands to add and remove occurrences (tool tip text will assist you).

Hopefully this prototype demonstrates how modern features in Uniface allow integration with other modern software systems.

 

Struct Member Assignment

I was reading Gerton’s blog on  Structs and its references, and I realized that he skillfully danced around some complex topics to avoid being distracted from his main focus. It is the only way to get your message across of course, but I was tempted to tackle one of those other tricky topics so I would like to show what happens exactly on struct assignment.

Let’s borrow one of Gerton’s structs and assume we have a struct variable myStructVar1, pointing to a struct in Uniface memory:

PD1

Now, the following two assignments have very different effects:

myStructVar2 = myStructVar1 ;- assignment (1)

myStructVar3 = $newstruct
myStructVar3->someNode = myStructVar1 ;- assignment (2)

I’m not talking about the obvious difference that the structure of myStructVar3 is slightly different, but what do these assignment statements do? The crucial difference is that the first assignment is to a Struct Variable, while the other assignment is to a Struct Member; this triggers other behavior.

In the first line, myStructVar2 simply becomes another reference to the struct in Uniface memory, which was already referenced by myStructVar1. Consequently, if the struct is modified through myStructVar1, the effect is seen in myStructVar2 and vice versa, because they point to the same memory space.

PD2

The assignment to a member of myStructVar3 is more complex. Structs cannot contain references to arbitrary other structs, so myStructVar3‑>someNode simply cannot refer to that same memory space. Instead, a copy is made of the struct referred to by myStructVar1, and it is created as a child Struct Node of myStructVar3. The assignment also dictates that the name of this node is someNode, so the copied struct is renamed from its original name (Node1) to the new name (someNode).

PD3

However, you may want to inherit the name from the assigned struct. You have two options to achieve this effect: either explicitly use the name of the source struct in the assignment, or prevent renaming. First, let’s explicitly use the proper name on assignment:

myStructVar3->"%%(myStructVar1->$name)" = myStructVar1 ;- assignment (3)

Alternatively, do not use any name in the assignment, but simply append a new child without any name assignment:

myStructVar3->*{-1} = myStructVar1 ;- assignment (4)

The syntax of this last assignment may puzzle you:  ->* is an operator which returns all children. The index between curly braces specifies where to insert or append the new node. A positive number is an absolute location among the existing child nodes, while -1 simply means: append at the end of the child node list.

Then there is one more thing: suppose we do not want to create a copy on assignment, suppose we DO want to assign the struct referred to by myStructvar1, as a member to some other struct, referred to by myStructVar2. This is a very valid requirement, as the effect is that other references to the struct will notice the effect of the assignment. How to do this?

It is quite simple, but requires you to think out of the box: do not assign the struct itself, but instead assign its parent:

myStructVar1->$parent = myStructVar3 ;- assignment (5)

PD4

Of course, if the struct referred to by myStructVar1 already had a parent, this assignment will detach the struct from its original parent.

In summary the different options, with a short one liner to characterize the effect:

myStructVar2 = myStructVar1                            ;- (1) copy a reference to the struct and assign the struct
myStructVar3->someNode = myStructVar1                  ;- (2) copy, rename and assign the struct
myStructVar3->"%%(myStructVar1->$name)" = myStructVar1 ;- (3) copy, (rename) and assign the struct
myStructVar3->*{-1} = myStructVar1                     ;- (4) copy and assign the struct
myStructVar1->$parent = myStructVar3                   ;- (5) attach the struct as a child

Pieter van Dijk

Developer in the Uniface Lab
During the development of Uniface 9.5, I contributed to the design of the Struct.
Currently I am actively using the Struct while working on the new version 10 IDE.

What else can you use Stucts for?

There is well deserved interest and anticipation in Uniface 9.6, however, I’m still digesting plenty of new things from 9.5.  In particular, I’ve been studying the use of Structs, and the data transformation statements that go with it.

You may recall that Structs were invented primarily to support the processing of complex data types that are used in Web Services.  However, procedural data transformation has much broader application that Web Services.  So even if you don’t plan to integrate with Web Services any time soon, you might have a good reason to use Structs in your legacy applications.

In 9.5 the focus of the data transformation has been on XML and Uniface component data structures.  XML often appears in the payload of SOAP messages used in Web Services, but it is also transported as separate files, sometimes accompanied by XML Schema files.  Some software routine generated these files and some other routine will read and interpret it.  If you consider that there may be file transfer, polling or messaging functions that support the transport of these XML files, then you could view these XML files as a part of an asynchronous call to a software process.  It just isn’t following a formal API, like Web Services.

So let’s compare 2 ways of getting the same job done.  Imagine that you have to build an office document from a template of some kind (to provide layout and pre-defined styles) and from data that is maintained by your Uniface application.  It doesn’t matter if it’s a spread sheet or a textual document.  I am comparing the use of an API, such as COM objects for Microsoft Office, versus the XML file(s) that is stored within the final office document file (these days, Open Office Org, and Microsoft Office documents, are really zipped archives of other files that contain everything needed to reconstruct the document).

API calls may be the safest way to build such a documents, as vendors will often publish an API, along with promises (usually kept)  to keep the API compatible into the future, whilst being free to change document structures without notice (and so their structure is not often documented).

However, a series of API calls may be difficult to comprehend, as the vendor usually has to keep their interfaces at a high level of abstraction and quite generic.  The sequence of calls may not match the way that you have to process your own application data.  At least there is a formal error processing mechanism, even if you find it difficult to understand.  APIs are also potentially limited to certain platforms, or may not have a function that performs the task that you require.

XML files have an orderly structured composition which can be validated.  With some simple viewing tools, it is relatively easy to deduce a document’s data structure.  Prototyping XML file creation is quick as there is visual feedback on how the results appear.  On the down side, you may have built the document structure apparently correctly, but it may still contain errors that will make the document appear corrupt by the next software routine that processes it.  So testing and debugging may be more difficult.

Making a choice between 2 such approaches is made routinely by developers due to many factors.  Now developers can take into account the new Structs data type and data transformation statements.  After building a spread sheet for a customer recently, I’m considering building a tool to massage my iTunes library using Structs, after all, it’s just organizing your assets via an XML file!