Skip to content
shackbarth edited this page Sep 23, 2013 · 8 revisions

Dispatch is a technique that allows developers the ability to write a custom function in the database that's accessible to the client. Like the other database access functions, the control flow passes straight through the datasource, so no additional coding in node is ever necessary. Unlike the other database access functions, you can write dispatch functions to execute any arbitrary, custom command against the database.

By convention we attach dispatchable functions to business objects in the XM namespace, and put them in the enyo-client/database/source/xm/javascript directory (although some dispatchable functions that are fundamental to the framework live in lib/orm/source/xt/javascript.) The XM business object that you attach the dispatchable function to does not need to be a real business object with an actual orm. In this example we'll pick something arbitrary.

Step 1

Enter the following code into the new file enyo-client/database/source/xm/javascript/metric_count.sql

select xt.install_js('XM','MetricCount','xtuple', $$
/* Copyright (c) 1999-2013 by OpenMFG LLC, d/b/a xTuple. 
   See www.xtuple.com/CPAL for the full text of the software license. */

(function () {

  if (!XM.MetricCount) { XM.MetricCount = {}; }

  XM.MetricCount.isDispatchable = true;

  XM.MetricCount.getMetricCount = function(searchTerm) {
    var ret,
      sql = "select count(*) from metric where metric_name like '%' || $1 || '%';";
        
    searchTerm = searchTerm || "";

    if (!XT.Data.checkPrivilege('MaintainAllIncidents')) { return null };

    ret = plv8.execute(sql, [searchTerm]);
    return JSON.stringify(ret);
  };
  XM.MetricCount.getMetricCount.description = "Returns a count of metrics matching the search term";
  XM.MetricCount.getMetricCount.params = {
    searchTerm: {type: "String", description: "Free-text filter term"}
  };
}());
$$ );

The whole thing looks like javascript, because it's written in plv8, but the first and last lines show that we're actually running a SQL function.

A few things to note:

  • Now that we've defined XM.MetricCount to be dispatchable, then we can add as many functions as we want and they can all be accessed by the client. Keep security in mind! In this example we enforce the MaintainAllIncidents privilege, just to show how it can be done.
  • Dispatchable functions give the user direct access to the database, so DO NOT attempt to do this if you are not fully aware of the danger of SQL injection attacks. Use parameterized queries as best defense against SQL injection, and use XT.format() to dynamically reference table or column names.
  • The dispatchable functions can take any arguments and return any result. The client is expected to honor whatever signature you set up here.
  • The description and params attributes of the function allow our REST Discovery Document to identify this function as a service.
  • What this function actually does is return the count of metrics that contain the parameter search string. This is a perfectly useless thing to do.

Step 2

Add this file to enyo-client/database/manifest.js

    "xm/javascript/metric_count.sql",

Step 3

Build the database

$ cd /path/to/xtuple
$ ./scripts/build_app.js --databaseonly

Step 4

Access from the client. Just to prove how it can be done, run the following code in the javascript console:

XM.ModelMixin.dispatch(
  'XM.MetricCount', 
  'getMetricCount', 
  ['BOL'], 
  {
    success: function(response) {
      console.log("success!", response[0].count); 
    }
  }
);

We identify the name of the object and the name of the function as the first two parameters. Our third parameter is an array of parameters for the dispatchable function itself -- in this case we know that the function expects a single string. The fourth parameter can contain a success or error function.

This dispatchable function's response is an array, but if we had wanted to we could have changed the return value in plv8 to return the first row only. Whatever plv8 returns is faithfully passed up to the client, so it's simply necessary to use the same signature on both sides, no matter what it is.

If you're inside of a model, you don't need to use the class-level static function XM.ModelMixin.dispatch. You can just run this.dispatch() with the same four parameters.