How to crud combined object

Introduction Table description Main principles The YCOMBD class
The YCOMB class The YCOMB representation The YCOMB_CSTD script The YCOMB_RSTD script

Introduction

In version 6 platform, a "Combined Object" is a type of object where a unique table containing a key with two components has multiple records associated with a given value of the first key component.

In this mode, the screen has a header and a grid.
* The header includes the first component of the key and additional fields with the same value for all records.
* The grid displays a row for each record with the same first key value.

While the generation of the CRUD code for this type of version 6 object is not automated, the new version 7 supervisor enables the creation of these objects as explained in the following example:

Table description

The table 'YCOMB [YCO]' to be handled has the following structure (technical columns are not listed):

ColumnTypeDescriptionPlace
YGRPCharacter 10GroupHeader
YNAMCharacter 80Group descriptionHeader
YSGRPCharacter 5Group memberLine
YTEXTCharacter 40Member textLine
YDATEDateMember DateLine
YNUMDecimal 9.2Member valueLine

'YCO0' is the unique key in the table. This key has no duplicates and is made up of two components: YGRP+YSGRP.

The principles of the CRUD on a Combined Object

The principles of handling a Combined Object are the following:

The 'YCOMBD' class definition

This class has the following characteristics:

As there are no particular controls on this class, there is no script associated with the class; however, one can be added if necessary.

The 'YCOMB' class definition

This class has the following characteristics:

The 'YCOMB' representation

This representation has the following characteristics:

The 'YCOMB_CSTD' script

Header Read method Insertion method Update method
Delete method Subprograms Events on collection Events on properties

The script implements the CRUD method for the combined object. The 'YCOMB' class is not persistent; therefore, the AREAD, AINSERT, AUPDATE, and ADELETE events are used. This is located in the script just after the '$METHOD' label in case 'CURPTH' is empty.

Additionally, the following two events: 'AREAD_AFTER' and 'ADDLINE_AFTER' have to be handled on every 'YCOMBD' record. When this happens, 'CURPTH' is equal to 'YCOMBD'.

Header

The beginning of the script is as follows:
CODECODE CODEsh
###############
# METHODS
###############
$METHODS
Case CURPTH
    When ""
        Case ACTION
            When "AREAD"                  : Gosub AREAD
            When "AINSERT"                : Gosub AINSERT
            When "AUPDATE"                : Gosub AUPDATE
            When "ADELETE"                : Gosub ADELETE
        Endcase
    When "YCOMBD"
        Case ACTION
            When "AREAD_AFTER"   : Gosub YCOMBD_AREAD_AFTER
            When "ADDLINE_AFTER" : Gosub YCOMBD_ADDLINE_AFTER
        Endcase
Endcase
Return

Read method

The 'AREAD' method performs a reading loop on the 'YCOMBD' table. For every existing record, the 'ADDLINE' method is invoked on the 'YCOMBD' collection to add a line at the end of the table. Then, The standard 'AREAD' method is used on the line instance to fill the record. The loop process stops if any error is found. This corresponds to the following code:
CODECODE CODEsh
$AREAD
Local File YCOMB [YCO]
Local Integer ILINE

  For [YCO] Where YGRP=this.YGRP
    ILINE = fmet this.ADDLINE("YCOMBD",CST_ALASTPOS)
    [L]ASTATUS = fmet this.YCOMBD(ILINE).AREAD([F:YCO]YGRP,[F:YCO]YSGRP)
    # The syntax Break condition means that if condition is true (ie 1), a Break 1 is done (Break 0 does nothing)
    Break [L]ASTATUS>=[V]CST_AERROR
  Next
Return

Insertion method

Consistency checks must be performed on the insertion method:

The corresponding sub-program is 'CTL_CONSISTENCY'.

A loop is performed to insert all of the lines with 'CST_ANEW' as the line status. While in insertion mode, the only other status that can be encountered is 'CST_ANEWDEL'.

Controlling that 'this.YCOMBD(ILINE)' is not null is useless in this case because the instance collection has been created by only adding lines at the end of the table, and because the deletion done is exclusively logical. The code is as follows:
CODECODE CODEsh
$AINSERT
Local Integer ILINE

# Consistency controls
  Gosub CTL_CONSISTENCY : If [L]ASTATUS>=[V]CST_AERROR : Return : Endif

# Loop on every line that has to be created
  For ILINE=1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = CST_ANEW
        [L]ASTATUS = fmet this.YCOMBD(ILINE).AINSERT()
        Break ([L]ASTATUS>=[V]CST_AERROR)
      Endif
    Endif
  Next
Return

Update method

The same first control is performed on the update method.

Three loops handle the different modifications that are made on the lines:

The code is as follows:
CODECODE CODEsh
$AUPDATE
Local Integer ILINE

  Gosub CTL_CONSISTENCY : If [L]ASTATUS>=[V]CST_AERROR : Return : Endif

# Delete the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YVOMB(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_ADEL
        [L]ASTATUS = fmet this.YCOMBD(ILINE).ADELETE()
        If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
      Endif
    Endif
  Next

# Update the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_AUPD
        [L]ASTATUS = fmet this.YCOMB(ILINE).AUPDATE()
        If [L]ASTATUS>=[V]CST_AERROR : Return : Endif
      Endif
    Endif
  Next

# Insert the lines
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      If this.YCOMBD(ILINE).ASTALIN = [V]CST_ANEW
        [L]ASTATUS = fmet this.YCOMBD(ILINE).AINSERT()
        Break [L]ASTATUS>=[V]CST_AERROR
      Endif
    Endif
  Next
Return

Delete method

A loop is initiated on every line that invokes the 'DELETE' method. The loop stops when an error occurs.

The code is as follows:
CODECODE CODEsh
$ADELETE
Local Integer ILINE
  For ILINE= 1 To maxtab(this.YCOMBD)
    If this.YCOMBD(ILINE)<>null
      [L]ASTATUS = fmet this.YCOMBD(ILINE).ADELETE()
      Break [L]ASTATUS>=[V]CST_AERROR
    Endif
  Next
Return

The CTL_CONSISTENCY subprogram

This subprogram performs a loop on the YCOMBD collection. If at least a line is found, LINE_FOUND is set to 1. A second loop, concatenated with the first one, checks whether the same YGRP value has been used on another line. If this is the case, an error is invoked and the loop is stopped.
CODECODE CODEsh
# Check the consistency
$CTL_CONSISTENCY
Local Shortint LINE_FOUND
Local Integer IL, JL

  For IL=1 To maxtab(this.YCOMBD)
    If this.YCOMB(IL)<>null
      If find(this.YCOMB(IL).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
        LINE_FOUND=1
        For JL= IL+1 To maxtab(this.YCOMBD)
          If this.YCOMB(JL)<>null
            If find(this.YCOMB(JL).ASTALIN,[V]CST_ADEL,[V]CST_ANEWDEL)=0
              If this.YCOMB(IL).YSGRP= this.YCOMB(JL).YSGRP
                [L]ASTATUS = fmet this.ASETERROR("YGRP", this.YCOMB(IL).YSGRP -":"-mess(94,139,1),[V]CST_AERROR)
                Break 2
              Endif
            Endif
          Endif
        Next JL
      Endif
    Endif
  Next IL
  If LINE_FOUND=0
    [L]ASTATUS = fmet this.ASETERROR("",mess(178,123,1),[V]CST_AERROR)
  Endif
Return

Events on the 'YCOMB' collection

Two events are necessary to properly manage the collection:

This provides the following code:
CODECODE CODEsh
$YCOMB_AREAD_AFTER
# Assign ASTALIN to CST_ALL (they have the value 'CST_ANEW' just after AREAD method)
this.ASTALIN = [V]CST_ALL
Return

$YCOMB_ADDLINE_AFTER
# To initialize properties of the header
this.YGRP = this.APARENT.YGRP
this.YNAM = this.APARENT.YNAM
Return

Events called on the properties

The following additional controls must be done on the properties (after the '$PROPERTIES' label in the script below):

This provides the following code:
CODECODE CODEsh
$PROPERTIES
  # If YGRP or YNAM have been modified, perform a loop to update all the lines
  Case CURPRO
    When "YGRP"
      Case ACTION
        When 'PROPAGATE'
          Local Integer IL
          For IL= 1 To maxtab(this.YCOMBD)
            If this.YCOMBD(IL)<>null
              this.YCOMBD(IL).YGRP = this.YGRP
            Endif
          Next IL
      Endcase
    When "YNAM"
      Case ACTION
        When 'PROPAGATE'
          Local Integer IL
          For IL= 1 To maxtab(this.YCOMBD)
            If this.YCOMBD(IL)<>null
              this.YCOMBD(IL).YGRP = this.YGRP
            Endif
          Next IL
      Endcase
  Endcase
Return

The script associated with the 'YCOMB' representation

This script manages the list of codes by using a table in memory. The code is as follows:

CODECODE CODEsh
#########################
# Representation YCOMB
#########################

###############
# METHODS
###############
$METHODS
Case CURPTH
   When ""
     Case ACTION
       When "AQUERY_DECODE_CRITERIA_AFTER" : Gosub AQUERY_DECODE_CRITERIA_AFTER
       When "AQUERY_PRIMARYKEYS_AFTER"     : Gosub AQUERY_PRIMARYKEYS_AFTER
       When "AQUERY_OPEN_AFTER"            : Gosub AQUERY_OPEN_AFTER
       When "AQUERY_TRANS_AFTER"           : Gosub AQUERY_TRANS_AFTER
       When "AQUERY_CLOSE_AFTER"           : Gosub AQUERY_CLOSE_AFTER
     Endcase
Endcase
Return

#################### Standard Query Events #########################

$AQUERY_DECODE_CRITERIA_AFTER
Raz NBPRO
NBPRO += 1
TBPRO(NBPRO) = "YGRP" : TBTYP(NBPRO) = 7 : TBPTH(NBPRO) = "YCOMBH.YGRP" : TBFIL(NBPRO) = "[LNK_]YGRP"
NBPRO += 1
TBPRO(NBPRO) = "YNAM" : TBTYP(NBPRO) = 7 : TBPTH(NBPRO) = "YCOMBH.YNAM" : TBFIL(NBPRO) = "[LNK_]YNAM"
Return

$AQUERY_PRIMARYKEYS_AFTER
ASTDKEY = "[LNK_]YGRP"
Return

$AQUERY_OPEN_AFTER
Local File YCOMB [QRY_YC]
Local Integer I : I=0
Local Char TYGRP(12)(1..), TYNAM(40)(1..)
For [QRY_YC]YCO0(1)
 I+=1
 TYGRP(I) = [F:QRY_YC]YGRP
 TYNAM(I) = [F:QRY_YC]YNAM
Next

# A test must be done on I (this will be fixed later)
# On empty arrays, for behaves as if 32,768 lines were here!
If I<>0
  Local File (Char YGRP(100),Char YNAM(100)) From Variable TYGRP,TYNAM As [LNK_]
Else
  Local File YCOMB [LNK_]
Endif
Return

$AQUERY_TRANS_AFTER
this.YCOMB.YGRP = [LNK_]YGRP
this.YCOMB.YNAM = [LNK_]YNAM
Return

$AQUERY_CLOSE_AFTER
Close Local File [LNK_]
Return