Console

The DynamicWhere console sample demonstrates using Dynamic Where clauses (DADynamicWhereClause) and Dynamic Select to request a subset of the records available in a schema's DADataTable. The sample demonstrates 3 different ways to compose a Dynamic Where clause to pass to the getDataTable:select:where: method of DARemoteDataAdapter which will retrieve the records.

Getting Started

The Console sample is typically located in /Developer/RemObjects Software/Samples/Data Abstract/Console/DynamicWhere, though you may have installed the Data Abstract for Cocoa and it's samples in another location.

To build it, you will of course need Xcode, and like all the samples provided with Data Abstract for Cocoa you will need to be running the Relativity Server with the DASamples Domain and the Simple Schema available.

Lastly this sample makes use of a convenience method (DALogTable) provided by a class extension to NSArray that we ship with Data Abstract for Cocoa. It is actually a #define method that uses one of three new log methods added to NSArray to print the contents of a DADataTable in a pretty fashion to the console using NSLog. To use this in your own code you must add the following to your import statements #import <DataAbstract/NSArray+DADataTableLog.h>. Please note that this class extension is intended for test purposes only.

Running the Sample

The sample when run sets up a connection to an instance of Relativity Server (Step 1). It then creates a Dynamic Where clause from a block of XML to request the Users table where the Type field is equal to 3 (Step 2). The next clause is composed from an NSPredicate object that specifies that we want to match records where the Role field contains the word "manager" (Step 3). The third clause is the most complex, it uses 3 NSPredicates to compose a NSCompoundPredicate where we want to filter the table for only those records in the Users table where the role is "Manager" and their name begins with a "J", or the userId is either 20, 22 or 24 (Step 4). Lastly we re-use the Dynamic Where clause from the previous step, and show retrieving the results with an asynchronous version of getDataTable:select:where: (Step 5).

Examining the Code

The code for creating the connection to the server and handling logging in is covered by other samples. In this section we shall focus solely on Steps 2 through 5 which handle the creation of the DADynamicWhereClause objects and retrieving the records.

Using XML for a Dynamic Where clause (Step 2)

In Data Abstract for Cocoa, Dynamic Where clauses can be constructed from either XML statements or from NSPredicate or NSCompoundPredicate objects. Here we demonstrate composing a multi-line XML statement with fixed arguments rather than dynamically supply them, which you could do. See the Dynamic Where page to learn more about the different types of expressions available and the XML you will need to use them.

The dynamicWhereClauseWithXmlString: method will create and return a DADynamicWhereClause object for you to use. It is important to note that the class returned is merely a wrapped for the XML and that no validation of the XML is performed. If there are any typos they will be caught by the server at runtime which will generate an ROException object.

To retrieve the filtered table we use the getDataTable:select:where: method of DARemoteDataAdapter. It takes three arguments; the first is the name of the table we want to retrieve, the second is an array field names we want to selectively retrieve - this uses the Dynamic Select1 feature of Data Abstract, the final argument is the DADynamicWhereClause we created a moment ago.

This request will return all rows from the table Users where their Type is equal to 3, and that the returned table rows should only contain the "Name", "Type" and "Role" fields.

NOTE If the table name, or the field names do not exist then an ROException will be raised and should be handled appropriately.

NSString *dynamicWhereXML =
        @"                                                                           \n"
        @"  <query                                                                   \n"
        @"    version='5.0'                                                          \n"
        @"    xmlns='http://www.remobjects.com/schemas/dataabstract/queries/5.0'>    \n"
        @"    <where xmlns=''>                                                       \n"
        @"      <binaryoperation operator='Equal'>                                   \n"
        @"        <field>Type</field>                                                \n"
        @"        <constant type='Integer' null='0'>3</constant>                     \n"
        @"      </binaryoperation>                                                   \n"
        @"    </where>                                                               \n"
        @"  </query>                                                                 \n";

NSLog(@"Generating DADynamicWhereClause from XML %@", dynamicWhereXML);
DADynamicWhereClause *filterClause = [DADynamicWhereClause dynamicWhereClauseWithXmlString:dynamicWhereXML];

DADataTable *table = [dataAdapter getDataTable:@"Users"
                                        select:@[@"Name", @"Type", @"Role"]
                                         where:filterClause];

Using an NSPredicate for a Dynamic Where clause (Step 3)

As an alternative to composing a Dynamic Where clause with XML, you can instead use the native Cocoa NSPredicate class. This is a simpler approach that requires fewer lines of code and feels more natural. There is nothing special you need to do in terms of formatting the predicate, you build it as you normally would.

The dynamicWhereClauseWithPredicate creates and returns an instance of DADynamicWhereClause using the supplied NSPredicate object. It is important to note that the class returned is merely wraps the NSPredicate object and that no validation of the specified field names is performed. If there are any typos they will be caught by the server at runtime, which will generate an ROException object.

To retrieve the filtered table we use the getDataTable:select:where: method of DARemoteDataAdapter. It takes three arguments; the first is the name of the table we want to retrieve, the second is an array field names we want to selectively retrieve - this uses the Dynamic Select feature of Data Abstract, the final argument is the DADynamicWhereClause we created a moment ago.

This request will return all rows from the table Users where their Role contains the string "manager", and that the returned table rows should only contain the "Name", "Type" and "Role" fields.

NSString *userRolePattern = @"manager";
NSPredicate *filterPredicate = [NSPredicate predicateWithFormat:@"Role CONTAINS[cd] %@", userRolePattern];
NSLog(@"Select Managers");
NSLog(@"NSPredicate %@", filterPredicate);
filterClause = [DADynamicWhereClause dynamicWhereClauseWithPredicate:filterPredicate];

table = [dataAdapter getDataTable:@"Users"
                           select:@[@"Name", @"Type", @"Role"]
                            where:filterClause];

Using an NSCompoundPredicate for a Dynamic Where clause (Step 4)

Building on the previous step, Data Abstract for Cocoa will accept much more complicated NSPredicates which are built using multiple NSPredicates and NSCompoundPredicates.

The dynamicWhereClauseWithPredicate creates and returns an instance of DADynamicWhereClause using the supplied NSPredicate object. It is important to note that the class returned is merely wraps the NSPredicate object and that no validation of the specified field names is performed. If there are any typos they will be caught by the server at runtime, which will generate an ROException object.

To retrieve the filtered table we use the getDataTable:select:where: method of DARemoteDataAdapter. It takes three arguments; the first is the name of the table we want to retrieve, the second is an array field names we want to selectively retrieve - this uses the Dynamic Select feature of Data Abstract, the final argument is the DADynamicWhereClause we created a moment ago.

In the example we are building a where clause, where we want people who are Managers and whose name starts with "J", or users who have the Id 20, 22 or 24. For all rows that match we want to have the "Id", "Name", "Type" and "Role" fields returned.

// users with role - manager (both sales manager and income managers)
userRolePattern = @"manager";
NSPredicate *roleCondition = [NSPredicate predicateWithFormat:@"Role CONTAINS[cd] %@", userRolePattern];

// users that name begins with "J"
NSString *userNamePattern = @"J";
NSPredicate *nameCondition = [NSPredicate predicateWithFormat:@"Name BEGINSWITH %@", userNamePattern];

// set of userID to select
NSArray *userIds = @[@20, @22, @24];
NSPredicate *idCondition = [NSPredicate predicateWithFormat:@"Id IN %@", userIds];

// Building final condition ((roleCondition AND nameCondition) OR idCondition)
NSPredicate *compoundAndCondition = [NSCompoundPredicate andPredicateWithSubpredicates:@[roleCondition, nameCondition]];
NSPredicate *finalCondition = [NSCompoundPredicate orPredicateWithSubpredicates:@[compoundAndCondition, idCondition]];

NSLog(@"Select Managers with name started with 'J' OR users with Id 20, 22, 24");
NSLog(@"NSPredicate %@", finalCondition);
filterClause = [DADynamicWhereClause dynamicWhereClauseWithPredicate:finalCondition];

table = [dataAdapter getDataTable:@"Users"
                           select:@[@"Id", @"Name", @"Type", @"Role"]
                            where:filterClause];

Using an asynchronous request with a Dynamic Where clause (Step 5)

This last step takes the DADynamicWhereClause (filterClause) from the previous step, and uses the asynchronous method beginGetDataTable:select:where:withBlock: instead of getDataTable:select:where:.

This means that the request to the server for the data will be spun off into a background thread that will execute the supplied block upon completion. The method takes four arguments; the first is the name of the table we want to retrieve, the second is an array field names we want to selectively retrieve - this uses the Dynamic Select feature of Data Abstract, the third argument is the DADynamicWhereClause we created in the previous step and the final argument is the block that will be executed when the data is returned..

The while loop simply keeps the program running until the background request is completed and sets the done boolean to YES.

static BOOL done = NO;

NSLog(@"Begin to select data ...");
[dataAdapter beginGetDataTable:@"Users"
                        select:@[@"Id", @"Name", @"Type", @"Role"]
                         where:filterClause
                     withBlock:^(DADataTable *t) {
    NSLog(@"Data has been retrieved");
    DALogTable(t);
    done = YES;
}];

NSLog(@"Waiting for completion asynchronous GetData call...");
while(!done && [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
NSLog(@"Done!");

Example Output

This is an example of the output you will see when the sample is run.

Dynamic Where sample has been started.
Target URL is http://localhost:7099/bin.
RO SDK layer is configured.
RO DataAbstract layer is configured.
Trying to login with login string User=simple;Password=simple;Domain=DASamples;Schema=Simple...
Login successfull

STEP 2. Using plain XML as DynamicWhere  ...
Generating DADynamicWhereClause from XML                                                                            
  <query                                                                   
    version='5.0'                                                          
    xmlns='http://www.remobjects.com/schemas/dataabstract/queries/5.0'>    
    <where xmlns=''>                                                       
      <binaryoperation operator='Equal'>                                   
        <field>Type</field>                                                
        <constant type='Integer' null='0'>3</constant>                     
      </binaryoperation>                                                   
    </where>                                                               
  </query>                                                                 
TABLE: Users (7 rows from 7)
-----------------------------------------------------------
| Name                  | Type    | Role                  |
-----------------------------------------------------------
| Brian L. Rowles 124   | 3       | Guest                 |
| Angela W. Vanover     | 3       | Guest                 |
| Anna H. Kugler dfdf   | 3       | Guest                 |
| Randy R. Howard       | 3       | Guest                 |
| Kenny S. Lay          | 3       | Guest                 |
| Maryann C. Bachmann df| 3       | Guest                 |
| Lillie R. Schroeder   | 3       | Guest                 |
-----------------------------------------------------------

STEP 3. Using NSPredicate ...
Select Managers
NSPredicate Role CONTAINS[cd] "manager"
TABLE: Users (9 rows from 9)
-----------------------------------------------------------
| Name                  | Type    | Role                  |
-----------------------------------------------------------
| Gale Dalton           | 1       | Income Manager        |
| Matthew Decker        | 1       | Income Manager        |
| Joseph Henson234      | 1       | Income Manager        |
| Jennifer Kent         | 1       | Sales Manager         |
| Sandy Manning         | 1       | Sales Manager         |
| Glenn Cunningham      | 1       | Sales Manager         |
| Marcy Collins         | 1       | Sales Manager         |
| Kirsten Rosario       | 1       | Sales Manager         |
| Merle Frank           | 1       | Sales Manager         |
-----------------------------------------------------------

STEP 4. Using Complex Compound NSPredicate ...
Select Managers with name started with 'J' OR users with Id 20, 22, 24
NSPredicate (Role CONTAINS[cd] "manager" AND Name BEGINSWITH "J") OR Id IN {20, 22, 24}
TABLE: Users (5 rows from 5)
---------------------------------------------------------------------
| Id      | Name                  | Type    | Role                  |
---------------------------------------------------------------------
| 4       | Joseph Henson234      | 1       | Income Manager        |
| 5       | Jennifer Kent         | 1       | Sales Manager         |
| 20      | Anna H. Kugler dfdf   | 3       | Guest                 |
| 22      | Kenny S. Lay          | 3       | Guest                 |
| 24      | Lillie R. Schroeder   | 3       | Guest                 |
---------------------------------------------------------------------

STEP 5. The same as STEP 3 but Asynchronous ...
Begin to select data ...
Waiting for completion asynchronous GetData call...
Data has been retrieved
TABLE: Users (5 rows from 5)
---------------------------------------------------------------------
| Id      | Name                  | Type    | Role                  |
---------------------------------------------------------------------
| 4       | Joseph Henson234      | 1       | Income Manager        |
| 5       | Jennifer Kent         | 1       | Sales Manager         |
| 20      | Anna H. Kugler dfdf   | 3       | Guest                 |
| 22      | Kenny S. Lay          | 3       | Guest                 |
| 24      | Lillie R. Schroeder   | 3       | Guest                 |
---------------------------------------------------------------------

Done!
Program ended with exit code: 0

NOTE: For clarity the date and process name and ID have been removed from the sample text above


  1. Dynamic Select provides a means to request only the columns you need from a table row.