Introduction

Enzo Server
  Installation
  Quick Start
  Core Features
    Async Calls
    ConnectionStrings
    Edge Cache
    HTTP Access
    Scheduling
    Views
  Advanced Capabilities
    Change Data Capture
  Administration
    Configuration Settings
    Logins & ACL
    Auditing
    Current Executions
    Linked Server
    SSL

  User Guides
     Sharding
     Sharding Overview

     SharePoint

   Adapters
    All Adapters


  SDK
    Overview
    Installation
    DevHost
    Create A Simple Adapter
    Handler Columns

    Advanced SDK Concepts
      Handler Decorators
      Dynamic Columns
      Table & Table Enumerators
      Virtual Tables

/sdk/handlerdecorators




Handler Decorators


You can create a handler with a decorator (the @ symbol) that allows you to obtain the name of a remote resource (such as a SalesForce table name) or a configuration setting that should be used instead of the default one.

Handler decorators allow you to call a handler and specifying an argument value directly as part of the table name. In this example we are calling the GetListItems (using the list tablename of the handler), and asking for the USStates SharePoint list:

SELECT * FROM SharePoint.list@USStates

Handler Decorators are most useful for SELECT, INSERT, DELETE and UPDATE operations. They are supported with LinkedServer calls as long as the columns returned are known at design time.


Uses

There are two primary scenarios in which decorators are useful:

  • Resource Names:
    In some cases, you may need to build an adapter for which the list of remote resources (or objects/tables) is not known at design time. For example it is not possible to known ahead of time the list of SharePoint lists that a customer has created when building the SharePoint adpater.

    Using the decorator in this way is not strictly necessary, since the name of the remote object could simply be passed in as an argument to the handler. Using the decorator simply makes it easier to call the handler:

    SELECT * FROM SharePoint.list@USStates

  • Dynamic Configurations:
    In some cases you may want your adapter to work with any number of configuration settings without having to use the _configUse command (which allows you to switch the current configuration setting). This makes it easy to use different settings without logging off and back on.

    SELECT * FROM CSV.data@config2

You can use a decorator the way you want; the above two use cases are the most commonly used so far, but you can leverage this mechanism in any way you deem useful.


Example: Resource Name

In this example the handler decorator is used to specify a remote SharePoint list name as part of the table name. The decorator is mapped to the listName argument of the handler, so that you do not have to specify it as part of a WHERE clause.

RegisterHandler("GetListItems,List@",
    HandlerOptions.Select | HandlerOptions.NoExec,
    "Get items from an existing SharePoint list (or view)",
    new[] { "SELECT * FROM SharePoint.list@mylist1" },
    GetListItems,
    new [] { "viewName|The name of the view to use.||@" } 
    );

The viewName argument is automatically set based to USStates in the above command; it is considered a required argument.

To specify a space within the name of the decorator, use the square brackets:

SELECT * FROM SharePoint.[list@US States List]



Here is a sample GetListItems method implementation that accesses the decorator:

private EventResult GetData(object sender, ExecEventArgs e)
{
    EventResult result = new EventResult(e);

    // Extract the decorator if found:
    // 
    // select * from SharePoint.list    
    // select * from SharePoint.[list@list1]
    // 

    string viewName = null;
    
    // get the decorator 
    // use TryGetArg for centralized code if you are not sure the handler has a given argument
    e.TryGetArg("viewName", out viewName, null);

    // is viewName null? if so, the viewName was not specified... throw an error    
    if (viewName == null)
    {
        result.ResultCode = 50000;
        result.ResultMsg = "The viewName argument is required";
    }
    else
    {
        // DO THE WORK HERE...
    }

    return result;
}


Example: Dynamic Configuration

In this example the handler decorator is used to specify a configuration setting other than the default one. This is useful for adapters that define a schema for a remote data set as part of its configuration settings.

RegisterHandler("GetData,Data@",
    HandlerOptions.Select,
    "Get data from a no-sql data source",
    new[] { 
        "SELECT * FROM MyAdapter.data",
        "SELECT * FROM MyAdapter.data@config1"
        },
    GetData,
    new [] { "definitionName|The name of the config setting to use.||@" } 
    );



You may also use the decorator to pass additional arguments separated by a column for example. For example this call contains both a configuration setting name (config1) and a sub-specifier (table1):

select * from adapter.[list@config1,table1]



A sample implementation code of the GetData method is presented below, with support for a sub-specifier.

private EventResult GetData(object sender, ExecEventArgs e)
{
    EventResult result = new EventResult(e);

    // Extract config name and sub-specifier if found
    // 
    // select * from adapter.list
    // select * from adapter.[list@config1]
    // select * from adapter.[list@config1,table1]
    // 

    string definitionName = null;
    string subSpecifier = null;

    // get the config name to load
    // use TryGetArg for centralized code if you are not sure the handler has a given argument
    e.TryGetArg("definitionName", out definitionName, e.Settings.ConfigName);

    string thisDefinition = definitionName;	// the config name provided, or the default config name

    // Is a specifier provided with a comma separator? 
    if (definitionName.Contains(','))
    {
      thisDefinition = definitionName.Split(',')[0]; // config1
      subSpecifier = definitionName.Split(',')[1];   // table1
    }

    // Load the specified settings (or the default setting if none provided)
    Config.SettingsCollection settings =
      (definitionName != null) ?
      e.AllSettings[thisDefinition] :
      e.Settings;


    // get a config setting called "url"
    string url = settings["url"].ToString();

    // DO THE WORK HERE...
    
    return result;
}