OShell Script comments
The OShell script in the example demonstrates some typical features. Besides elementary script commands as changing data sources (cd) or data collections (cc), OShell supports embedded OSI scripts. When you enter script data directly via console, blocks (beginning with .. .do or ... begin)are processed only after terminating the block with an end command. More details one may find in Database Utilities.
The first command (cd) selects the data source (Sample) as being defined as section in the .ini file. Thus, one may switch between different data sources by defining different data sources in the ini-file. After the data source has been opened, a collection (extent) is selected (cc). After selecting a data collection, one may browse data in the data collection or change to sub collections (references or relationships).
cd Sample
cc Company
Similar the li command lists the keys for all instances in the collection. Since the selected collection is the Company extent, a list of all company names will be displayed. We added the result of the command in the example below.
In order to run a command for all instances in a collection, the command to be executed might be preceded by an fa meta-command. Thus, the subsequent commands will list the number of cars and employees for each company in the collection. The lav command lists a single attribute value, which might be an access path, also.
li
Any company
Best company
My company
NO company
Your company
fa lav cars.count
cars.count=12
cars.count=17
cars.count=3
cars.count=15
cars.count=7
fa lav employees.count
employees.count=100
employees.count=92
employees.count=105
employees.count=114
employees.count=89
In order to change to a new extent, the path should start with a '/', which means to search from the database root rather than from the current collection. When the extent has been defined in a name space, a scoped name has to be passed. Since the syntax for command line parameters is restricted, it is save to add string delimiters for the collection path.
Finally, the collection has changed to Persons.
cc '/Person::Persons'
Most API functions for Value and Property can be called directly from within OShell. Thus, the collection count could be retrieved by calling count as well as other interface functions. When passing parameters, those are parsed separated by spaces. Parameters always should be passed within quotes.
When calling API functions, those will print the function result on console. Function not returning a value just report successful termination.
Below, we replaced the sfc (set filter condition) command by the filter function from the Property API. The result is the same, but in this case the return value from the filter function will be displayed on console.
cc /Employee
count
count returns: 500
// sfc "sex == 'male'" replaced by
filter "sex == 'male'"
filter returns: sex == 'male'
relativeCount
relativeCount returns: 258
cc '/Person::Persons'
count
count returns: 1,000
When embedding OSI script within OShell, the current collection is considered as the context, in which the script is running. In the example, this is the Persons extent with a filter condition. Simple OSI expressions can be called just preceding the operand by the osi meta command. Usually, however, the OSI script to be executed will be embedded in an osi do ... end block.
Such a do block (in contrast to an osi begin ... end block) creates a copy of the collection handle, i.e. the original settings in the selected OShell collection will be copied but not be affected by any operation in the OSI script (e.g. setting another filter).
This block may contain just some statements or, as in the example below, a VARIABLES and a PROCESS section. In order to write data to the console, Message() might be called.
osi do
VARIABLES
int child_count;
int distance = 0, dist = 0;
int min_dist = 100, max_dist = 0;
int dcount = 0;
PROCESS
filter('age > 65 && employee.count == 0');
Message('Persons probably retired (over 65 and not employed): ' + relativeCount);
top();
while ( next() )
child_count += children.count;
Message('Total number of children: ' + child_count);
filter("");
top();
while ( next() )
while ( children.next() ) {
dist = age-children.age;
if ( min_dist >= dist ) min_dist = dist;
if ( max_dist <= dist ) max_dist = dist;
distance += age-children.age;
++dcount;
}
Message('Average age distance between children and parents: ' + distance/dcount);
Message(' Minimum/maximum distance is: ' + (string)min_dist + '/' + (string)max_dist);
end