Managing CRUD Combined Objects

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

Introduction

A combined object is made of a unique table containing a key with two components. This table has multiple records that are associated with a given value of the first key component.

In this mode:

While the generation of the CRUD code for this type of object is not automated, objects can be created using the supervisor.

Table description

Table "YCOMB [YCO]" has the following structure (technical columns are not listed):

Column Type Description Place
YGRP Character 10 Group Header
YNAM Character 80 Group description Header
YSGRP Character 5 Group member Line
YTEXT Character 40 Member text Line
YDATE Date Member Date Line
YNUM Decimal 9.2 Member value Line

"YCO0" is the unique key of the table. It has no duplicates and it is made of two components: YGRP+YSGRP.

Main principles

"YCOMBD" class definition

This class has the following characteristics:

As there are no particular controls on this class, there is no script associated with it. However, you can add one if necessary.

"YCOMB" class definition

This class has the following characteristics:

"YCOMB" representation

This representation has the following characteristics:

"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. They are located in the script, right after the $METHOD label in case "CURPTH" is empty.

Additionally, 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:

sh
###############
# 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. The standard AREAD method is then used on the line instance to fill the record. The loop process stops if any error is found. This corresponds to the following code:

sh
$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".

In this case, there is no need to make sure this.YCOMBD(ILINE) is not null because the instance collection was created by only adding lines at the end of the table, and because the deletion is exclusively logical.

The code is as follows:

sh
$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 initial control is performed on the update method.

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

The code is as follows:

sh
$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:

sh
$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

"CTL_CONSISTENCY" subprogram

This subprogram performs a loop on the "YCOMBD" collection. If at least one 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.

The code is as follows:

sh
# 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:

sh
$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 performed on the properties (after the $PROPERTIES label in the script below):

This provides the following code:

sh
$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

Script associated with the "YCOMB" representation

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

sh
#########################
# 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