You are on page 1of 20

Advanced Development Standards &

Conventions
for Caché

Atlas Development Corporation, 6351 Owensmouth Avenue., Suite 101, Woodland Hills, California 91364 USA
Tel+1 818 340 7080 Fax+1 818 340 7079 E-mail info@atlasdev.com http://www.atlasdev.com
CONTENTS
Projects 3
Tables 4
Maps 6
Global Structures 7
Forms 10
Menus 12
Reports 13
Views 14
Queries 15
Routines 16

2
Advanced Development Standards

Document: Standards.doc
Release: version n/a
Revision Date: 021501
 2001 Atlas Development Corporation. All rights reserved.

3
PROJECTS

Project
A project is the set of all programming objects (tables, forms, menus,
reports, views, queries, routines, and globals) used in an application.

System Areas
A project is divided up into system areas. Each system area is a logical
grouping of programming objects based on their usage within a project.
(e.g. “Accounting”, “Forecasting”, “Shipping”, etc.) Each programming
object belongs to one system area. The choice of which system area a
particular programming object belongs has no affect on the function of the
application. System areas are used only to assist in project control and
ease of programming.

System Area Alias


Each system area is given a two or three letter code (e.g. “ACT” for the
Accounting system area, “FOR” for the Forecasting system area, and
“SH” for the Shipping system area).

4
Advanced Development Standards

TABLES

Table Name
Tables are named “[System Area Alias]_[Table Moniker]” (e.g.
ACT_AccountsReceivable). Components are separated by an underscore.
The table moniker should always be the grammatical singular, not the
plural (e.g. “Person” rather than “Persons”).
This format ensures that tables are sorted by system area alias in Caché
lookups. It also tells the programmer what system area a table belongs to
by reading the table name.

Table Alias
Each table is given a one to five character code (e.g. “AR” for
ACT_AccountsReceivable). Table aliases should be unique within a
system area. The table alias is also used in other naming conventions.
Standard Caché does not recognize this attribute.

Table Description
After the table description, the following information should be added and
right justified:
([Table Alias], [Table Number]). For example
“Accounts Receivable (AR, 253)”.
A/Frame maps this to read each table’s table alias. The table number in
the description is useful when performing functions where the table name
is displayed but the developer would like to know the table number as
well.

Table Field Name


Table fields are named “[Table Alias]_[Field Moniker]” (e.g.
AR_AmountOutstanding). Components are separated by an underscore.
This convention is convenient when writing embedded SQL statements
with implicit joins. If all table aliases are unique across the project, it also
assures that the field names are unique across the project.

LabWorks specific instruction – DL April 11, 2008

5
While adding a field to an older codeset the field column number has to be
maintained. If a certain field is not required in a particular codeset, a
dummy field (placeholder) needs to be created.
It should have the following properties -
Name - <table alias>_FLD+<column number>
Description – Reserved For Later Version
Data Type – Text
Computed Field – Yes. Computation is S {Field}=””

Row ID Name
The rowID field is named “[Table Alias]_RowID” (e.g. AR_RowID).
Components are separated by an underscore.

Parent Reference Name


The parent reference field is named “[Table Alias]_[Parent’s Table
Alias]_[ParRef]” (e.g. AR_CUST_ParRef). Components are separated by
underscores.

Designative Reference Name


All designative reference names end with “DR” (e.g. CUST_CityDR).
This convention is convenient when writing embedded SQL statements
with implicit joins.

Child Subscript
The child counter is named “[Table Alias]_ChildSub” (e.g.
AR_ChildSub).

Table A/Routine Name


An A/Routine is an M routine that is used to hold all customized code
associated with a Caché table definition. A/Routines are automatically
created from a standard template. There are tables A/Routines, form
A/Routines, etc.
The convention for naming table A/Routines is “XT_[Table Number]”
(e.g. XT253). In A/Frame, the table A/Routine naming convention can be
customized.

6
Advanced Development Standards

Table A/Routine Tags


The table A/Routine tags are:
PRFILINS Pre filing insert
PRFILUP Pre filing update
PRFILDEL Pre filing delete
POFILINS Post filing insert
POFILUPD Post filing update
POFILDEL Post filing delete
VALINS Insert validation
VALUPD Update validation
VALDEL Delete validation
NXTLV# Next override subroutine for level #
CO# Computed value for the field with column
no. #
CONU# Computed null for the field with column no.
#
AV# Additional validation for field with column
no. #
EI# External to internal conversion for the field
with column no. #
IE# Internal to external conversion for the field
with column no. #
DEF# Default value for the field with column no.
#
RQIF# Required if for the field with column no. #

7
MAPS

Master Map Name


A table’s master map is named “Data Master Map - [Table Alias]” (e.g.
Data Master Map - AR). This map will appear first in Caché lookups.

Index Map Names


Index maps are named “Index - [Field Moniker 1] / [Field Moniker 2] ...”
where the field monikers are from the indexed fields (e.g. Index -
CustomerDR). The index name quickly describes the contents of the
index.

8
Advanced Development Standards

GLOBAL STRUCTURES

Global Name
A non-child table’s global is named “[System Area Alias][Table Alias]”
(e.g. ^ACTCUST). (The components are not separated.)
For child tables, the global name is the same as the parent table. The
global name indicates to which system area and table the child table
belongs. Also, the table name indicates what global stores the table’s data.

Surrogate Keys
Surrogate keys, rather than primary keys, should be used for most tables.
There are numerous advantages to this:
þ If the definition of a table’s primary key changes after a table
is built, many changes must be made to the table’s underlying
global. With surrogate keys, these definitions never change.
þ If the data of a primary key changes, all referencing tables
must have their designative references modified to reflect the
change. Surrogate key values never change.
þ Primary keys need to be defined early in the data modeling
process. This step is delayed or eliminated when surrogates
key are used.
þ With primary keys, uniqueness must be enforced. If a primary
key is built off multiple fields, this must be enforced with
code. With surrogate keys, uniqueness of row ID’s is
automatically assured.
þ With surrogate keys, the global subscript structure is consistent
across all tables. If primary keys are used, global structures
cannot be standardized.
þ With surrogate keys, designative references are simpler and
usually smaller than when primary keys are used.
The disadvantages of using surrogate keys over primary keys are:
þ Tables with surrogate keys generally require an additional
index based on the logical primary key.
þ When primary keys are used, designative references hold
meaningful data so the need to reference extended tables is
reduced.

9
Since the number of advantages greatly outweighs the disadvantages, the
use of surrogate keys is advised. One exception is the case of static
dictionary tables, which have a simple unchanging code indicating the
dictionary record. In these cases, the code can be used as the row ID and
therefore, tables that reference the dictionaries will store the code itself.
In many cases, this will reduce the need to reference the dictionary table.
Since the code is a single field, the standard global structure is not
affected.

Subscript Structure
For non-child tables, the subscript is the row ID field (e.g.
^ARCUST([CUST_RowID]).
For child tables, the subscript is the same as the parent table’s subscript
structure followed by “[Table Alias]_RowID” (e.g.
^ARCUST([CUST_RowID],“AR”,[AR_RowID])).
This standard effectively segregates children under a parent.

Counter Node
The counter node is used to assign surrogate key values
For non-child tables, the counter node is at the global’s “0” subscript (e.g.
^ACTCUST(0)). This must be incremented using $$next code on the
default M expression of the table’s row ID field. Because the “0” node is
reserved for the counter, the first value of the special access code should
be set to one (1) in the access path specification of the master map’s row
ID.
For child tables, the counter is at the “0” level of the child table portion of
the global (e.g. ^ACTCUST([CUST_RowID],“AR”,0)). This must be
incremented using $$next code on the default M expression of the table’s
child subscript field. Because the “0” node is reserved for the counter, the
first value of the special access code should be set to one (1) in the access
path specification of the master map’s row ID.

Master Map Data


For single line fields, all the data resides in one node. The order of the
fields has no effect on the application or SQL code so it can be entered in
alphabetical order. The delimiter should be a control character (e.g.
$C(127)). This is convenient because that is the way Caché presents the
fields in the lookup. For multi-line fields, we advise that the storage type

10
Advanced Development Standards

be set to “One Per Node”. The node for each field is a short descriptive
code (e.g. “DESC” for description).

Index Subscripts
The index subscripts are the following:
0
“Field Name 1”
“Field Name 2”
...
Field Value 1
Field Value 2
...
Row ID Component 1
Row ID Component 2

For example, for a parent table, the index subscripts would


“^ACTCUST(0,”CUST_CityDR”,[CUST_CityDR],CUST_RowID)”.
For a child table, the index subscripts would be
“^ACTCUST(0,”AR_Amount”,[AR_Amount],
[ACT_Customer.CUST_RowID], [AR_ChildSub])”.
This structure efficiently stores all indexes out of the way at the “0” node.
By keeping the indexes in the same global as the data, a global’s system
management is greatly simplified.
Other more advanced global structures are advised but exceed the scope of
this document.

Index Data
Usually, no data is stored in the nodes of an index map. However, field
values may be stored (denormalized) in the index to enhance lookup
performance.

Global Structure Sample


The following is a sample global which demonstrates these standards.
^ACTCUST(0,”CUST_City”,3,2)=“”

11
^ACTCUST(0,”CUST_City”,6,1)=“”
^ACTCUST(0,”AR_Amount”,34512,1,2)=“”
^ACTCUST(0,”AR_Amount”,68862,2,1)=“”
^ACTCUST(0,”AR_Amount”,83535,1,1)=“”
^ACTCUST(0)=2
^ACTCUST(1)=“Customer 1”_$C(127)_6
^ACTCUST(1,”AR”,0)=2
^ACTCUST(1,”AR”,1)=“1234”_$C(127)_83535
^ACTCUST(1,”AR”,2)=“1236”_$C(127)_34512
^ACTCUST(1,”DESC”,0)=2
^ACTCUST(1,”DESC”,1)=“Description 1”
^ACTCUST(1,”DESC”,2)=“Description 2”
^ACTCUST(2)=“Customer 2”_$C(127)_3
^ACTCUST(2,”AR”,0)=1
^ACTCUST(2,”AR”,1)=“6432”_$C(127)_68862

12
Advanced Development Standards

FORMS

Form Name
Forms are named “[System Area Alias] [Form Moniker], followed by the
form number, right justified and in parentheses (e.g. ACT Account
Review (345)). Components are separated by a space.
This format ensures that forms are sorted by system area alias in Caché
lookups. The form number is used for program calls to form A/Routines.

Window Name
Windows are named “[Form Number][single alphabetical letter] [Window
Description]” (e.g. 345A Account Review). The single alphabetical letter
is used to identify the specific window.
The window name appears on the status line during runtime, so that the
form (window) can be immediately be identified by the form number.
This assists in debugging and remote communication with users.

Form Field Names


Form fields are named “FO_[Field Moniker]” (e.g. FO_TodaysDate).
Components are separated by an underscore.
Branching fields are named “BR_[Field Moniker]”. Components are
separated by an underscore.
This effectively groups these fields in Caché lookups.

Form A/Routine Name


Atlas Development’s naming convention for form A/Routines is “XF”
followed by the form number (e.g. XF345). In A/Frame, the form
A/Routine naming convention can be customized.

Form A/Routine Tags


The form A/Routine tags are:
 FORMFILE Form filing
 FORMDEL Form deletion
 PRFORM Pre-form trigger
 PORTRV Post retrieval

13
 POFORM Post form
 PRWINA Pre window for window “A”.
PRWINB for window “B”
 POWINA Post window for window “A”
 COFO# Computed value for form field #
 CONUFO# Computed null for form field #
 AVFO# Additional validation for form field
#
 EIFO# External to internal for form field #
 IEFO# Internal to external for form field #
 DEFFO# Default value for form field #
 RQIFFO# Required if for form field #
 PRFO# Pre field trigger for form field #
 POFO# Post field trigger for form field #
 PRTB# Pre field trigger for table field #
 POTB# Post field trigger for table field #
 OPEN# Programmed lookup open #1
 FETCH# Programmed lookup fetch #1
 CLOSE# Programmed lookup close #1

14
Advanced Development Standards

MENUS

Menu Name
Vertical menus are named “[System Area Alias} [Menu Moniker]” (e.g.
ACT Billing Functions). Components are separated by a space.
Horizontal menus are named “[System Area Alias] H [Menu Moniker]
(e.g. ACT H Acct Review). Components are separated by spaces.

Menu A/Routine Name


The menu A/Routine is named “XM[Menu Number]” (e.g. XM121). The
components are not separated.

15
REPORTS

Report Name
Reports are named “[System Area Alias] [Report Moniker]” (e.g. ACT
BillingSummary). The components are separated by a space.

Report Field Name


Report fields are named “RPT_[Field Moniker]” (e.g. RPT_Summary).
The components are separated by an underscore. This groups report fields
together in Caché lookups.

16
Advanced Development Standards

VIEWS

View Name
Views are named “[System Area Alias]_[View Moniker]” (e.g.
ACT_BillingView). Components are separated by an underscore.

17
QUERIES

Query Name
Queries are named “[System Area Alias]_[Query Moniker]” (e.g.
ACT_OverdueCheck). Components are separated by an underscore.

18
Advanced Development Standards

ROUTINES

Routine Name
A routine which is not an A/Routine is named “X[SystemAreaAlias]#”
where # is a sequential number (e.g. XAR1). This implies that every
routine belongs to a system area.

Variable Names
When using the “SELECT * INTO” syntax to populate an array, the array
is named “[Table Alias]” (e.g. AR).
When a variable stores the value of a table’s row ID, the variable is named
“[TableAlias]ROW” (e.g. ARROW).

Cursors
1. The cursor name should start with the table alias of the table queried,
followed by a simple modifier to differentiate between other cursors
querying against the same table in the same routine.
2. Please note that the cursor name should not be more than six
characters long. The Cache SQL compiler will use the first six
characters of the cursor name to create local variables in the INT code.
If multiple cursors share the same first six characters in their names,
there will be redundant variable names in the INT code. This should
be avoided.
3. Following the “FETCH” command, use the line “I SQLCODE=0 D”
instead of “Q:SQLCODE”. This forces subsequent code in your loop
to be contained in its own dot level scope, which will avoid scope
conflict with similarly named variables like “SQLCODE”.
4. In general, you should add the line “N SQLCODE” immediately after
“I SQLCODE=0 D”, which should be in its own dot level scope to
avoid confusion with references to SQLCODE defined previously in
your code.
Please see the cursor code example on the next page.

19
Cursor Code Example:

CO25(LOROW)
#;
N SQLCODE,RETVAL,SIGNED
S RETVAL=""
#;
&SQL(DECLARE LOOCS CURSOR FOR
SELECT LOOC_ABNSigned
INTO :SIGNED
FROM ORD_LOOCode
WHERE LOOC_LO_ParRef = :LOROW)
#;
&SQL(OPEN LOOCS)
F D Q:(SQLCODE)
. &SQL(FETCH LOOCS)
. I SQLCODE=0 D
.. N SQLCODE
.. ; *** YOUR CODE GOES HERE ***
&SQL(CLOSE LOOCS)
Q RETVAL
#;======
#;

20

You might also like