Using Dynamic Dictionaries

In the following example, a dynamic dictionary performs an object sort based on member attributes. The publications property is a collection of Publications. This example shows the use of the reimplemented Dictionary class startKeyGeq method to start the iteration at a specific point and demonstrates passing a variable list of key parameters where the keys are not known at compile-time.

vars
    dynaDict : DynaDictionary;
    pub      : Publication;
    iter     : Iterator;
begin
    create dynaDict transient;
    // set the membership of our dynamic dictionary
    dynaDict.setMembership(Publication);
    // specify the ytdSales, royalty, and descending pubDate dictionary keys
    dynaDict.addMemberKey("ytdSales", false, false);
    dynaDict.addMemberKey("royalty", false, false);
    // specify descending key so that most recent titles appear first
    dynaDict.addMemberKey("pubdate", true, false);
    // complete key definition
    dynaDict.endKeys(false);
    // copy publication instances into the dynamic dictionary
    publications.copy(dynaDict);
    // display all publications with more than 1000
    // sales (ytd) in sorted order
    iter := dynaDict.createIterator;
    // start the iteration where ytdSales >= 1000
    // since the dynadict has 3 keys we must pass
    // keys to the startKeyGeq method
    dynaDict.startKeyGeq(1000, null, null, iter);
    while iter.next(pub) do
        write pub.name & " " & pub.ytdSales.String &
                   pub.royalty.String & " " & pub.pubdate.String;
    endwhile;
epilog
    // ensure we delete transients
    delete iter;
    delete dynaDict;
end;

The following example shows the use of a dynamic dictionary that orders employees by age and length of service. These key values are returned by the getAge and getLengthOfService methods in the Employee class. As the key values are not properties, the dynamic dictionary cannot be defined using member keys and can only be defined using external keys.

vars
    dyna : DynaDictionary;
    emp : Employee;
    root : Root;
    iter : Iterator;
begin
    create dyna transient;
    dyna.setMembership(Employee);
    dyna.addExternalKey(TimeStampInterval,8,false,false); // age
    dyna.addExternalKey(TimeStampInterval,8,false,false); // length service
    dyna.endKeys(false);                                  // no duplicates
    root := Root.firstInstance;
    foreach emp in root.allEmployeesByName do
        dyna.putAtKey(emp.getAge, emp.getLengthOfService, emp);
    endforeach;
    iter := dyna.createIterator();
    while iter.next(emp) do
        write emp.name & Tab & emp.dob.shortFormat;
    endwhile;
epilog
    delete dyna;
    delete iter;
end;

The following examples demonstrate the use of a dynamic dictionary in an application-specific query where a suitable dictionary type is not available in the object model. These examples show the use of a key path specification and the bracket ([]) substring operators to perform a dictionary lookup and use the model Department, Employee, and DepartmentSet (a set of Department) classes, with the following partial definitions.

Employee
(
referenceDefinitions
    department:     Department explicitInverse, readOnly;
)
Department
(
referenceDefinitions
    manager:        Employee explicitInverse, readOnly;
)

The following AQController class is a query controller, which has a singleton transient instance at run time. This class defines the managers exclusive property of type DynaDictionary.

AQController
(
referenceDefinitions
    managers : DynaDictionary implicitMemberInverse, protected;
jadeMethodDefinitions
    // public interface operations
    getManagerByDeptName(deptName: String): Manager;
    // implementation method
    loadManagers(departments: DepartmentSet) protected;
)

The following method is called when an AQController instance is initialized and sets up and then populates the managers dynamic dictionary. You could use a notification mechanism to ensure that the managers dictionary is kept current when departments are added or deleted or managers are changed.

AQController::loadManagers
loadManagers(departments: DepartmentSet) protected;
vars
    dept : Department;
begin
    // set the membership of our dynamic dictionary
    managers.setMembership(Employee);
    // the single key is the keypath: department.name
    managers.addMemberKey("department.name", false, false);
    // end key specification, and do not allow duplicates as the
    // model does not allow two departments with the same name
    managers.endKeys(false);
    foreach dept in departments do
        managers.add(dept.manager);
    endforeach;
end;

The following method looks up the managers dynamic dictionary to find the manager by department name.

AQController::getManagerByDeptName
getManagerByDeptName(deptName: String): Manager;
begin
    return managers[deptName].Manager;
end;