Defining Data Classes (and User Types)

Data classes are data types so they have names that are unique not just among data classes, but all data types. Data class members, of which there must be at least one, have a name that is unique within the data class, and a predefined data type which can be another data class. Members also have population restraints. The minimum population is either 0 (nulls allowed) or 1 (not null). The maximum is either a positive value indicating a specific limit (usually 1), or 0 for 'unlimited'. Any maximum over 1 means the member is an array.

In the configs data classes are defined by the <class> tag, and their members by the <member> subtag. For the purpose of data model specification, the <class> tag only needs an attribute of name, and the <member> tag only needs attributes of name, type, minPop and maxPop. However, generation of default forms and form handlers, directly from data class definitions, benefits from the unorthodox approach of embedding display control parameters with the data class definitions. Accordingly, the <member> tag has additional optional attributes. The complete set are as follows:-

Name of member
Data type of Member
minPop Minimum value population (0 or 1).
maxPop Maximum value population (N or 0).
lim Alternative to min and max Pop. Of the form "min,max".
numLo Minimum numeric or lexical value
numHi Maximum numeric or lexical value
seq Display order within form
exp Export order
fldspec Field specification (would include data type)
cols Width of HTML input field in number of characters.
rows Height of HTML input field in number of lines (TEXTBOX only)
size Total size limit as a number of characters, if applicable.
html HTML type (if not the default for the data type)
desc Description of member
Title Of field in default form.

Note that if a fldspec is supplied (as recommended), the type attribute and the display attributes, cols, rows, size and html, should not be. The following example defines the data class for contacts from a typical 'Contact-Us' page:-

<class name="contact">
    <member lim="1,1" name="salute" fldtype="salute"/>
    <member lim="1,1" name="fname"  fldtype="string"/>
    <member lim="1,1" name="lname"  fldtype="string"/>
    <member lim="1,1" name="email"  fldtype="emaddr"/>
    <member lim="0,1" name="corp"   fldtype="string"/>
    <member lim="0,1" name="posn"   fldtype="string"/>
    <member lim="1,1" name="desc"   fldtype="string"/>
    <index member="email" unique="false"/>
</class>

Specifying Data Repositories and Indexes

Data object repositories are created by the <repos> tag, which has compulsory attributes of name and class. Repository names are usually chosen to reflect the data class, but as it is possible to have multiple repositories of the same data class, names need only be unique among repositories. The repository name does matter however, as it is used to name the repository data and index files. Note that these files reside in the directory specified in the <webappCfg> datadir attribute.

The repository native data class dictates what form of data object the repository will store, but not how. Which object members if any, are indexed; whether values of these members are required to be unique, or be within a given range; and which members if any, will use RAM Primacy as the storage method, are all matters for the repository. By default, members are not indexed, and do not require values to be unique or to be within a value range. If an index is to apply or values are to be constrianed, then a <member> subtag is used to specify this. The below example creates the a repository for contacts, indexing on email address and requiring the email address to be unique.

    <repos class="contact" name="Contacts">
        <member name="email" index="true" unique="true"/>
    </repos>

Note that the data type of the member dictates what type of index is used, so it suffices for the index attribute to simply be true/false.

RAM Primacy Options

Both the <repos> tag and its <member> subtag have an optional method attribute which sets the storage method, respectively at the repository and member level. This will either be 'cache' (RAM Primacy) or 'store' (Persistent media only). Both methods commit data to persistent media as soon as it arises, but with RAM Primacy the data remains memory resident throughout runtime. Due to file buffering and an "Always Append, Never Insert" policy (AANI), all data writes are fast. However data reads which are usually more frequent, are subject to media access times. For reads, RAM Primacy is 5-10 times faster than SSD and around 1,000 times faster than a hard drive. RAM Primacy, which has the obvious cost of higher memory consumption, is intended for core, searchable data only. It should not be applied to TEXT members and cannot be applied to TXTDOC, TXTSRC or BINARY members. Setting method="cache" in the <repos> tag, will make all members use RAM Primacy, except for those of these types. To force a TEXT member to be memory resident, method="cache" would have to be set in a <member> subtag.

The <user> Tag

Registered users of webapps are of course, data objects held in a repository. However the applicable data class is a special case, so is defined by the <user> tag, instead of the <class> tag. The rules differ slightly. As with the <class> tag, the user data class name must be unique among all data types. There is also the same <member> subtag, however certain members are automatic and compulsory. The <user> tag also creates the user repository. There is no need to create the repository as a subsequent step.