The following example compares development of Stores 7 Informix 4gl sample application with Axional Studio. The application CUSTOMER can select, modify and create new customers.

1 Stores 7 4GL application

1.1 Using 4GL application

The following example shows how to make a customers query from California state.

1.2 Forms development with 4GL

Customer application allows to query and manage customers. It contains two files:

  • custform.per - to perform the QBE query and to display customer data.
  • d4_cust.4gl - to perform the query and data management processing on the cursor data.

1.2.1 Customer query and management form

The query by example (QBE) and the cursor with resulting data can be viewed using the custform.per.

Example

And it's defined in custform.per file.

Copy
DATABASE stores7

SCREEN
{


                           Customer Form

        Number      :[f000       ]
        Owner Name  :[f001           ][f002           ]
        Company     :[f003                ]
        Address     :[f004                ]
                     [f005                ]
        City        :[f006           ] State:[a0] Zipcode:[f007 ]
        Telephone   :[f008              ]

}

TABLES
customer

ATTRIBUTES
f000 = customer.customer_num, NOENTRY;
f001 = customer.fname;
f002 = customer.lname;
f003 = customer.company;
f004 = customer.address1;
f005 = customer.address2;
f006 = customer.city;
a0 = customer.state, UPSHIFT;
f007 = customer.zipcode;
f008 = customer.phone, PICTURE = "###-###-#### XXXXX";

1.2.2 d4_cust.4gl

The following 4gl application is used to manage customer form actions, including query, add, update or delete a customer.

Copy
GLOBALS
    "d4_globals.4gl"


FUNCTION customer()

    OPTIONS
        FORM LINE 7
    OPEN FORM customer FROM "custform"
    DISPLAY FORM customer
        ATTRIBUTE(MAGENTA)
    CALL ring_menu()
    CALL fgl_drawbox(3,32,3,42)
    CALL fgl_drawbox(3,61,8,7)
    CALL fgl_drawbox(11,61,8,7)
    LET p_customer.customer_num = NULL
    MENU "CUSTOMER"
        COMMAND "One-add" "Add a new customer to the database" HELP 201
            CALL unring_menu()
            CALL add_customer(FALSE)
            call ring_menu ()
        COMMAND "Many-add" "Add several new customers to database" HELP 202
            CALL unring_menu()
            CALL add_customer(TRUE)
            call ring_menu ()
        COMMAND "Find-cust" "Look up specific customer" HELP 203
            call unring_menu ()
            IF query_customer(23) THEN
                call ring_menu ()
                NEXT OPTION "Update-cust"
            END IF
            call ring_menu ()
        COMMAND "Update-cust" "Modify current customer information" HELP 204
            CALL unring_menu()
            CALL update_customer()
            call ring_menu ()
            NEXT OPTION "Find-cust"
        COMMAND "Delete-cust" "Remove a customer from database" HELP 205
            CALL unring_menu()
            CALL delete_customer()
            call ring_menu ()
            NEXT OPTION "Find-cust"
        COMMAND "Exit" "Return to MAIN Menu" HELP 206
            CLEAR SCREEN
            EXIT MENU
    END MENU
    OPTIONS
        FORM LINE 3
END FUNCTION


FUNCTION add_customer(repeat)
    DEFINE repeat INTEGER

    CALL clear_menu()
    MESSAGE "Press F1 or CTRL-F for field help; ",
            "F2 or CTRL-Y to return to menu"
    IF repeat THEN
        WHILE input_cust()
            ERROR "Customer data entered" ATTRIBUTE (GREEN)
        END WHILE
        CALL mess("Multiple insert completed - current screen values ignored", 23)
    ELSE
        IF input_cust() THEN
            ERROR "Customer data entered" ATTRIBUTE (GREEN)
        ELSE
            CLEAR FORM
            LET p_customer.customer_num = NULL
            ERROR "Customer addition aborted" ATTRIBUTE (RED, REVERSE)
        END IF
    END IF
END FUNCTION


FUNCTION input_cust()

    DISPLAY "Press ESC to enter new customer data" AT 1,1
    INPUT BY NAME p_customer.*
        AFTER FIELD state
            CALL statehelp()
            DISPLAY "Press ESC to enter new customer data", "" AT 1,1
        ON KEY (F1, CONTROL-F)
            CALL customer_help()
        ON KEY (F2, CONTROL-Y)
            LET int_flag = TRUE
            EXIT INPUT
    END INPUT
    IF int_flag THEN
        LET int_flag = FALSE
        RETURN(FALSE)
    END IF
    LET p_customer.customer_num = 0
    INSERT INTO customer VALUES (p_customer.*)
    LET p_customer.customer_num = SQLCA.SQLERRD[2]
    DISPLAY BY NAME p_customer.customer_num ATTRIBUTE(MAGENTA)
    RETURN(TRUE)
END FUNCTION

FUNCTION query_customer(mrow)
    DEFINE where_part CHAR(500),
           query_text CHAR(500),
           answer CHAR(1),
           mrow, chosen, exist SMALLINT

    CLEAR FORM
    CALL clear_menu()

    MESSAGE "Enter criteria for selection"
    CONSTRUCT where_part ON customer.* FROM customer.*
    MESSAGE ""
    IF int_flag THEN
        LET int_flag = FALSE
        CLEAR FORM
        ERROR "Customer query aborted" ATTRIBUTE(RED, REVERSE)
        LET p_customer.customer_num = NULL
        RETURN (p_customer.customer_num)
    END IF
    LET query_text = "select * from customer where ", where_part CLIPPED,
                        " order by lname"
    PREPARE statement_1 FROM query_text
    DECLARE customer_set SCROLL CURSOR FOR statement_1

    OPEN customer_set
    FETCH FIRST customer_set INTO p_customer.*
    IF status = NOTFOUND THEN
        LET exist = FALSE
    ELSE
        LET exist = TRUE
        DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA)
        MENU "BROWSE"
            COMMAND "Next" "View the next customer in the list"
                FETCH NEXT customer_set INTO p_customer.*
                IF status = NOTFOUND THEN
                    ERROR "No more customers in this direction" ATTRIBUTE(RED, REVERSE)
                    FETCH LAST customer_set INTO p_customer.*
                END IF
                DISPLAY BY NAME p_customer.*  ATTRIBUTE(MAGENTA)
            COMMAND "Previous" "View the previous customer in the list"
                FETCH PREVIOUS customer_set INTO p_customer.*
                IF status = NOTFOUND THEN
                    ERROR "No more customers in this direction" ATTRIBUTE(RED, REVERSE)
                    FETCH FIRST customer_set INTO p_customer.*
                END IF
                DISPLAY BY NAME p_customer.*  ATTRIBUTE(MAGENTA)
            COMMAND "First" "View the first customer in the list"
                FETCH FIRST customer_set INTO p_customer.*
                DISPLAY BY NAME p_customer.*  ATTRIBUTE(MAGENTA)
            COMMAND "Last" "View the last customer in the list"
                FETCH LAST customer_set INTO p_customer.*
                DISPLAY BY NAME p_customer.*  ATTRIBUTE(MAGENTA)
            COMMAND "Select" "Exit BROWSE selecting the current customer"
                LET chosen = TRUE
                EXIT MENU
            COMMAND "Quit" "Quit BROWSE without selecting a customer"
                LET chosen = FALSE
                EXIT MENU
        END MENU
    END IF
    CLOSE customer_set

    CALL clear_menu()
    IF NOT exist THEN
        CLEAR FORM
        CALL mess("No customer satisfies query", mrow)
        LET p_customer.customer_num = NULL
        RETURN (FALSE)
    END IF
    IF NOT chosen THEN
        CLEAR FORM
        LET p_customer.customer_num = NULL
        CALL mess("No selection made", mrow)
        RETURN (FALSE)
    END IF
    RETURN (TRUE)
END FUNCTION


FUNCTION update_customer()

    CALL clear_menu()
    IF p_customer.customer_num IS NULL THEN
        ERROR "No customer has been selected; use the Find-cust option"
            ATTRIBUTE (RED, REVERSE)
        RETURN
    END IF
    MESSAGE "Press F1 or CTRL-F for field-level help"
    DISPLAY "Press ESC to update customer data; DEL to abort" AT 1,1
    INPUT BY NAME p_customer.* WITHOUT DEFAULTS
        AFTER FIELD state
            CALL statehelp()
            DISPLAY "Press ESC to update customer data; DEL to abort", "" AT 1,1
        ON KEY (F1, CONTROL-F)
            CALL customer_help()
        END INPUT
    IF NOT int_flag THEN
        UPDATE customer SET customer.* = p_customer.*
            WHERE customer_num = p_customer.customer_num
        CALL mess("Customer data modified", 23)
    ELSE
        LET int_flag = FALSE
        SELECT * INTO p_customer.* FROM customer
            WHERE customer_num = p_customer.customer_num
        DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA)
        ERROR "Customer update aborted" ATTRIBUTE (RED, REVERSE)
    END IF
END FUNCTION


FUNCTION delete_customer()
    DEFINE answer CHAR(1),
           num_orders INTEGER

    CALL clear_menu()
    IF p_customer.customer_num IS NULL THEN
        ERROR "No customer has been selected; use the Find-cust option"
            ATTRIBUTE (RED, REVERSE)
        RETURN
    END IF

    SELECT COUNT(*) INTO num_orders
        FROM orders
        WHERE customer_num = p_customer.customer_num
    IF num_orders THEN
        ERROR "This customer has active orders and can not be removed"
            ATTRIBUTE (RED, REVERSE)
        RETURN
    END IF

    PROMPT " Are you sure you want to delete this customer row? "
        FOR CHAR answer
    IF answer MATCHES "[yY]" THEN
        DELETE FROM customer
            WHERE customer_num = p_customer.customer_num
        CLEAR FORM
        CALL mess("Customer entry deleted", 23)
        LET p_customer.customer_num = NULL
    ELSE
        ERROR "Deletion aborted" ATTRIBUTE (RED, REVERSE)
    END IF
END FUNCTION

FUNCTION customer_help()
    CASE
        WHEN infield(customer_num) CALL showhelp(1001)
        WHEN infield(fname) CALL showhelp(1002)
        WHEN infield(lname) CALL showhelp(1003)
        WHEN infield(company) CALL showhelp(1004)
        WHEN infield(address1) CALL showhelp(1005)
        WHEN infield(address2) CALL showhelp(1006)
        WHEN infield(city) CALL showhelp(1007)
        WHEN infield(state) CALL showhelp(1008)
        WHEN infield(zipcode) CALL showhelp(1009)
        WHEN infield(phone) CALL showhelp(1010)
    END CASE
END FUNCTION


FUNCTION statehelp()
    DEFINE idx INTEGER

    SELECT COUNT(*) INTO idx
        FROM state
        WHERE code = p_customer.state
    IF idx = 1 THEN
        RETURN
    END IF

    DISPLAY "Move cursor using F3, F4, and arrow keys; press ESC to select state" AT 1,1
    OPEN WINDOW w_state AT 8,37
        WITH FORM "state_list"
        ATTRIBUTE (BORDER, RED, FORM LINE 2)

    CALL set_count(state_cnt)
    DISPLAY ARRAY p_state TO s_state.*
    LET idx = arr_curr()

    CLOSE WINDOW w_state
    LET p_customer.state = p_state[idx].code
    DISPLAY BY NAME p_customer.state ATTRIBUTE(MAGENTA)
    RETURN
END FUNCTION

2 Stores 7 Axional Example

First, we will see the same application using Axional Interface.

2.1 Using Axional

As with the 4gl, this example shows how to make a customers query from California state.

2.2 User guide

2.2.1 Query

When application is activated, it shows a QBE form. You can use common QBE command to perform any type of query.

2.2.2 Form

After the query is performed, a cursor with matching data from customer table is shown.

The form, automatically displays a toolbar with control options. These options include the ability to:

Number Icon Name Description
1 Scroll Scroll next or previous.
2 Query Recall query screen.
3 Reload Reload form object. (customers in this example)
4 Clear Reset the form to add new row (customers in this example).
5 Insert Insert the new data.
6 Update Save the modified form data.
7 Delete Delete the current row.
8 List view Toggle from form to grid layout.
9 Print Print to PDF or export to serveral formats including Excel, CSV.
10 Table manager Access to table manager tool to perform several operations (unload, SOAP export,...) on selected data (requires specific role).
11 Information Get information about source data including performance metrics (requires specific role).
12 Documentation Access to object documentation.
This image is the customer list view (nº8).

This image is the customer PDF (nº9).

3 Stores 7 Quick development

d4_cust.4gl + custform.per

3.1 Forms development

To create a form object just go to the physical dictionary of tables, where previously the table of the object that you want to create (customer) has been defined.

At the bottom of the screen you will find the Object Build Button, which will automatically create the customer object.


Before creating it, a window will be shown asking for the database where the object will be created and the type of renders to be used.


Once finished you can check that the form object has been created.


If the object is executed, the query screen...


...and the form screen will appear.

This operation should take less than 5 minutes (including the creation of physical tables).

4 Stores 7 Advanced development

4.1 How to modify form layout

The following example shows how to modify the form layout.

Within the object definition select the button Form layout.


Now you can define the new number of rows and columns that are needed inside the box.


Once you have selected the number of columns and rows, choose the field you need and drag it to the desired position.


When the field is dropped, the position is automatically saved.


Now, excuting again the form, the new layout is shown reflecting the changes.


This would be the result.

Again, this operation should take less than 5 minutes.

4.2 Define a Soft Reference

This example shows how to define a soft reference in the State field.

4.2.1 Implementation

The implementation of Filtering Helper is achieved by adding some settings to the desired table and columns. According to this configuration, the sistem handles to types of helpers:

  • Automatic helpers (Hard Reference) are created from the database constraints configuration.
  • Explicit helpers (Soft Reference) are defined by dictionary.

4.2.2 Helper definition

The Helper definition form contains all the necessary fields and componenents to define and maintain Filtering helpers. Each helper definition is identified by a table name and a method. The method generally corresponds to table column; it is not necessary but is useful when using automatic statements as we will see bellow.

Autocomplete statement

Each time the user types a character in the input field having an explicit Filtering Helper the Autocomplete statement is executed and the result of this statement is displayed to the user as an autocomplete list.

This achieved through an automatic SQL autocomplete statement, with table state and method code:

Copy
<select>
    <columns>
        state.code, state.sname
    </columns>
    <from table='state' />
    <where>
        (UPPER (state.code) LIKE UPPER ('%${q}%') OR
         UPPER (state.sname) LIKE UPPER ('%${q}%'))
    </where>
</select>

If the autocomplete statement is left blank and the method doesn't correspont with a valid column for the table defined in the helper, an SQL Syntax error will occur.

It is important to note the use of the ${q} clause in the statement; which references the input pattern typed by the user when autocomplete is requested.

Validation statement

The validation statement has two purposes: verify the integrity of the input value and gather some information related to the input value for filling the form with this data. This purposes are achieved by executing the Validation SQL statement when the field value changes.

As it happens with the autocomplete statement, leaving the Validation SQL statement blank entails the system to build an automatic statement using the helper definition table and method.

Example

The SQL validation statement executed for our helper with table state and method code:

Copy
<select>
    <columns>
        state.code
    </columns> 
    <from table='state' />
    <where>
        state.code = ${q} 
    </where>
</select>

If the validation statement is left blank and the method doesn't correspont with a valid column for the table defined in the helper, an SQL Syntax error will occur.

Validation SQL Statement accepts both native SQL or XSQL syntax, but Axional Studio Functional Roles will only be applied with the XSQL syntax.

Object data selector

Object data selector is enabled by specifying a column in the Help object box. If so, the object used as data selector corresponds with the table name identifying the helper. The defined column references the column of the destionation object to take the value from an place it in the source field.

Optionally, it could be defined a condition that will be added to the where clause of the destination object.

The main difference is that those expressions are literally replaced in the condition to be send as an object condition clause.

Example

In our case there is no condition, but this is a sample of a object data selector condition using variables:

Copy
customer.country = '${country}' AND customer.state = 'A'

The main consideration is that alphanumeric variables should be placed between quotes.

This operation has taken 3 minutes.

4.2.3 Define relation

Once having a proper catalog of helpers, it is the time of telling each field what helper will use and configure the relations between the form and the helper.

Column Description Value
Object Code of form object containing the field to assign the helper customer
Source Column Name of the field to apply the helper state
Destiny table Table identifying the applicable helper. Corresponds with the previously defined table. state
Method Method identifying the applicable helper. Corresponds with the previously defined method. code

This operation has taken 2 minutes.

4.3 How to make a form object

Every Axional application is composed of objects. Objects are defined as a set of transactions in a special database named dictionary.

A dictionary is a database that contains a collection of tables that allows programmers define application objects.

The basic structure of any Axional object is composed of:

  1. input, for the data that will be used to perform the subsequent process
  2. process, with the SQL or script code that will be applied on data using the previous input
  3. output, to define the output structure as a form, report, document, etc

The previous three components are mapped to the following Axional object components.

  1. The main SQL/XSQL statement, that will produce a resulsting cursor with data
  2. The input columns or variables, that will be used to filter the main cursor
  3. The output columns mapping, that will be used to map the output data into the desired render component (form, report, ...)


4.3.1 SQL/XSQL statement

Number Description
1 Specify as object code, in this case is customer, on Object section, the name of the table against the other one which user wants to make insertions, modifications and delete registers.
2

It is a short description of the object, it is used in the tabs. If this object is included as another tabs, the default system will show this tag as a link to access the object.

You can also use this description as the title of a Box.

3 Title or description of the object, which appears at the top of the screen when it is executed.
4 Render type
5 The functional group, as its name suggests, consists of a classification of the objects through which they can be grouped based on their characteristics and functional properties.
6 Select option READ / WRITE on Type section in order to indicate to the system that form can transact against main table of SQL query.
7

Object query is written on XML code and it must be selected some column of the table which user wants to do insertions, modifications and register deleted.

4.3.2 Inputs

All columns selected on SQL query whom user could filter when he access to the form.

It used to be a subset of all selected section on query.

If it isn't any column defined, form won't have filter page.

Column *

You can use an asterisk to use all the columns for filtering.

4.3.3 Outputs

All columns selected on SQL query that will be shown on execution object.

Automatic Generation

Exit sections will be generated automatically when object is executed for the first time.

Review table name and section

If query is composed with more than one table, it would necessary to review the table name assigned to each section.

4.3.4 Form layout

Insert

To create a form, first click on the insert button.

Select row and columns for boxes

Below is the form editor, which allows you to select the rows and columns that you want to insert the boxes.

Box type

Once you select the number of columns and rows, choose the type of box.

The different types of boxes are displayed on the left side of the form editor screen.

To select it you have to drag it to the desired position.

Select row and columns for fields

The next step is to define the number of rows and columns that are needed inside the box.

Select outputs

As with the selection of the type of boxes, the outputs are dragged to the desired position.

Select fields type

Once all the outputs have been placed, you should define the type of each field.

The selection method is the same as with the box type.

This operation should take less than 10 minutes.