1 /**
  2  * @fileOverview
  3  * @author <a href="https://www.labkey.org">LabKey</a> (<a href="mailto:info@labkey.com">info@labkey.com</a>)
  4  * @license Copyright (c) 2008-2016 LabKey Corporation
  5  * <p/>
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  * <p/>
 10  * http://www.apache.org/licenses/LICENSE-2.0
 11  * <p/>
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing permissions and
 16  * limitations under the License.
 17  * <p/>
 18  */
 19 
 20 /**
 21  * @namespace Query static class to programmatically retrieve, insert, update and
 22  *		delete data from LabKey public queries. <p/>
 23  *		{@link LABKEY.Query.selectRows} works for all LabKey public queries.  However,
 24  *		{@link LABKEY.Query.updateRows}, {@link LABKEY.Query.insertRows} and
 25  *		{@link LABKEY.Query.deleteRows} are not available for all tables and queries.
 26  *            <p>Additional Documentation:
 27  *              <ul>
 28  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=labkeySql">
 29  *                      LabKey SQL Reference</a></li>
 30  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
 31  *                      How To Find schemaName, queryName & viewName</a></li>
 32  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
 33  *                      <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a></li>
 34  *              </ul>
 35  *           </p>
 36  */
 37 LABKEY.Query = new function()
 38 {
 39     function sendJsonQueryRequest(config)
 40     {
 41         var dataObject = {
 42             schemaName : config.schemaName,
 43             queryName : config.queryName,
 44             rows : config.rows || config.rowDataArray,
 45             transacted : config.transacted,
 46             extraContext : config.extraContext
 47         };
 48 
 49         var requestConfig = {
 50             url : LABKEY.ActionURL.buildURL("query", config.action, config.containerPath),
 51             method : 'POST',
 52             success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
 53             failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
 54             jsonData : dataObject,
 55             headers : {
 56                 'Content-Type' : 'application/json'
 57             }
 58         };
 59 
 60         if (LABKEY.Utils.isDefined(config.timeout))
 61             requestConfig.timeout = config.timeout;
 62 
 63         return LABKEY.Ajax.request(requestConfig);
 64     }
 65 
 66     function getContentType(response)
 67     {
 68         //The response object is not actually the XMLHttpRequest object
 69         //it's a 'synthesized' object provided by Ext to help on IE 6
 70         //http://extjs.com/forum/showthread.php?t=27190&highlight=getResponseHeader
 71         return response && response.getResponseHeader ? response.getResponseHeader('Content-Type') : null;
 72     }
 73 
 74     function getSuccessCallbackWrapper(callbackFn, stripHiddenCols, scope, requiredVersion)
 75     {
 76         if (requiredVersion && (requiredVersion === 13.2 || requiredVersion === "13.2" || requiredVersion === 16.2)) {
 77             return LABKEY.Utils.getCallbackWrapper(function(data, response, options){
 78                 if (data && callbackFn)
 79                     callbackFn.call(scope || this, new LABKEY.Query.Response(data), response, options);
 80             }, this);
 81         }
 82 
 83         return LABKEY.Utils.getCallbackWrapper(function(data, response, options){
 84             if (data && data.rows && stripHiddenCols)
 85                 stripHiddenColData(data);
 86             if (callbackFn)
 87                 callbackFn.call(scope || this, data, options, response);
 88         }, this);
 89     }
 90 
 91     function stripHiddenColData(data)
 92     {
 93         //gather the set of hidden columns
 94         var hiddenCols = [];
 95         var newColModel = [];
 96         var newMetaFields = [];
 97         var colModel = data.columnModel;
 98         for(var idx = 0; idx < colModel.length; ++idx)
 99         {
100             if (colModel[idx].hidden)
101                 hiddenCols.push(colModel[idx].dataIndex);
102             else
103             {
104                 newColModel.push(colModel[idx]);
105                 newMetaFields.push(data.metaData.fields[idx]);
106             }
107         }
108 
109         //reset the columnModel and metaData.fields to include only the non-hidden items
110         data.columnModel = newColModel;
111         data.metaData.fields = newMetaFields;
112 
113         //delete column values for any columns in the hiddenCols array
114         var row;
115         for(idx = 0; idx < data.rows.length; ++idx)
116         {
117             row = data.rows[idx];
118             for(var idxHidden = 0; idxHidden < hiddenCols.length; ++idxHidden)
119             {
120                 delete row[hiddenCols[idxHidden]];
121                 delete row[LABKEY.Query.URL_COLUMN_PREFIX + hiddenCols[idxHidden]];
122             }
123         }
124     }
125 
126     function configFromArgs(args)
127     {
128         return {
129             schemaName: args[0],
130             queryName: args[1],
131             rows: args[2],
132             successCallback: args[3],
133             errorCallback: args[4]
134         };
135     }
136 
137     function getMethod(value)
138     {
139         if (value && (value.toUpperCase() === 'GET' || value.toUpperCase() === 'POST'))
140             return value.toUpperCase();
141         return 'GET';
142     }
143 
144     // public methods:
145     /** @scope LABKEY.Query */
146     return {
147 
148         /**
149          * An enumeration of the various container filters available. Note that not all
150          * data types and queries can contain that spans multiple containers. In those cases,
151          * all values will behave the same as current and show only data in the current container. 
152          * The options are as follows:
153          * <ul>
154          * <li><b>current:</b> Include the current folder only</li>
155          * <li><b>currentAndFirstChildren:</b> Include the current folder and all first children, excluding workbooks</li>
156          * <li><b>currentAndSubfolders:</b> Include the current folder and all subfolders</li>
157          * <li><b>currentPlusProject:</b> Include the current folder and the project that contains it</li>
158          * <li><b>currentAndParents:</b> Include the current folder and its parent folders</li>
159          * <li><b>currentPlusProjectAndShared:</b> Include the current folder plus its project plus any shared folders</li>
160          * <li><b>allFolders:</b> Include all folders for which the user has read permission</li>
161          * </ul>
162          */
163         containerFilter : {
164             current: "Current",
165             currentAndFirstChildren: "CurrentAndFirstChildren",
166             currentAndSubfolders: "CurrentAndSubfolders",
167             currentPlusProject: "CurrentPlusProject",
168             currentAndParents: "CurrentAndParents",
169             currentPlusProjectAndShared: "CurrentPlusProjectAndShared",
170             allFolders: "AllFolders"
171         },
172 
173 
174         /**
175          * Execute arbitrary LabKey SQL. For more information, see the
176          * <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=labkeySql">
177          * LabKey SQL Reference</a>.
178          * @param config An object which contains the following configuration properties.
179          * @param {String} config.schemaName name of the schema to query.
180          * @param {String} config.sql The LabKey SQL to execute.
181          * @param {String} [config.containerPath] The path to the container in which the schema and query are defined,
182          *       if different than the current container. If not supplied, the current container's path will be used.
183          * @param {String} [config.containerFilter] One of the values of {@link LABKEY.Query.containerFilter} that sets
184          *       the scope of this query. Defaults to containerFilter.current, and is interpreted relative to
185          *       config.containerPath.
186          * @param {Function} config.success
187                  Function called when the "selectRows" function executes successfully.
188                  This function will be called with the following arguments:
189                  <ul>
190                      <li>
191                          <b>data:</b> If config.requiredVersion is not set, or set to "8.3", the success handler will be
192                          passed a {@link LABKEY.Query.SelectRowsResults} object. If set to "9.1" the success handler will
193                          be passed a {@link LABKEY.Query.ExtendedSelectRowsResults} object. If set to "13.2" the succes
194                          handler will be passed a {@link LABKEY.Query.Response} object.
195                      </li>
196                      <li><b>responseObj:</b> The XMLHttpResponseObject instance used to make the AJAX request</li>
197                      <li><b>options:</b> The options used for the AJAX request</li>
198                  </ul>
199          * @param {Function} [config.failure] Function called when execution of the "executeSql" function fails.
200          *                   See {@link LABKEY.Query.selectRows} for more information on the parameters passed to this function.
201          * @param {Integer} [config.maxRows] The maximum number of rows to return from the server (defaults to returning all rows).
202          * @param {Integer} [config.offset] The index of the first row to return from the server (defaults to 0).
203          *        Use this along with the maxRows config property to request pages of data.
204          * @param {Boolean} [config.includeTotalCount] Include the total number of rows available (defaults to true).
205          *       If false totalCount will equal number of rows returned (equal to maxRows unless maxRows == 0).
206          * @param {String} [config.sort] A sort specification to apply over the rows returned by the SQL. In general,
207          * you should either include an ORDER BY clause in your SQL, or specific a sort specification in this config property,
208          * but not both. The value of this property should be a comma-delimited list of column names you want to sort by. Use
209          * a - prefix to sort a column in descending order (e.g., 'LastName,-Age' to sort first by LastName, then by Age descending).
210          * @param {Boolean} [config.saveInSession] Whether or not the definition of this query should be stored for reuse during the current session.
211          * If true, all information required to recreate the query will be stored on the server and a unique query name will be passed to the
212          * success callback.  This temporary query name can be used by all other API methods, including Query Web Part creation, for as long
213          * as the current user's session remains active.
214          * @param {Boolean} [config.includeDetailsColumn] Include the Details link column in the set of columns (defaults to false).
215          *       If included, the column will have the name "~~Details~~". The underlying table/query must support details links
216          *       or the column will be omitted in the response.
217          * @param {Object} [config.parameters] Map of name (string)/value pairs for the values of parameters if the SQL
218          *        references underlying queries that are parameterized. For example, the following passes two parameters to the query: {'Gender': 'M', 'CD4': '400'}.
219          *        The parameters are written to the request URL as follows: query.param.Gender=M&query.param.CD4=400.  For details on parameterized SQL queries, see
220          *        <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=paramsql">Parameterized SQL Queries</a>.
221          * @param {Double} [config.requiredVersion] If not set, or set to "8.3", the success handler will be passed a {@link LABKEY.Query.SelectRowsResults}
222                  object. If set to "9.1" the success handler will be passed a {@link LABKEY.Query.ExtendedSelectRowsResults}
223                  object. If set to "13.2" the success handler will be passed a {@link LABKEY.Query.Response} object.
224                  The main difference between SelectRowsResults and ExtendedSelectRowsResults is that each column in each row
225                  will be another object (not just a scalar value) with a "value" property as well as other related properties
226                  (url, mvValue, mvIndicator, etc.). In the LABKEY.Query.Response format each row will be an instance of
227                  {@link LABKEY.Query.Row}.
228          * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
229          *       generating a timeout error (defaults to 30000).
230          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
231          * @returns {Mixed} In client-side scripts, this method will return a transaction id
232          * for the async request that can be used to cancel the request
233          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
234          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
235          * @example Example, from the Reagent Request Confirmation <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=reagentRequestConfirmation">Tutorial</a> and <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=Confirmation">Demo</a>: <pre name="code" class="xml">
236          // This snippet extracts a table of UserID, TotalRequests and
237          // TotalQuantity from the "Reagent Requests" list.
238          // Upon success, the writeTotals function (not included here) uses the
239          // returned data object to display total requests and total quantities.
240 
241              LABKEY.Query.executeSql({
242                      containerPath: 'home/Study/demo/guestaccess',
243                      schemaName: 'lists',
244                      sql: 'SELECT "Reagent Requests".UserID AS UserID, \
245                          Count("Reagent Requests".UserID) AS TotalRequests, \
246                          Sum("Reagent Requests".Quantity) AS TotalQuantity \
247                          FROM "Reagent Requests" Group BY "Reagent Requests".UserID',
248                      success: writeTotals
249              });  </pre>
250 
251          * @see LABKEY.Query.SelectRowsOptions
252          * @see LABKEY.Query.SelectRowsResults
253          * @see LABKEY.Query.ExtendedSelectRowsResults
254          * @see LABKEY.Query.Response
255          */
256         executeSql : function(config)
257         {
258             var dataObject = {
259                 schemaName: config.schemaName,
260                 sql: config.sql
261             };
262 
263             // Work with Ext4.Ajax.request
264             if (config.saveInSession !== undefined && config.saveInSession !== null)
265                 dataObject.saveInSession = config.saveInSession;
266 
267             //set optional parameters
268             if (config.maxRows !== undefined && config.maxRows >= 0)
269                 dataObject.maxRows = config.maxRows;
270             if (config.offset && config.offset > 0)
271                 dataObject.offset = config.offset;
272             if (config.includeTotalCount != undefined)
273                 dataObject.includeTotalCount = config.includeTotalCount;
274 
275             if (config.containerFilter)
276                 dataObject.containerFilter = config.containerFilter;
277 
278             if (config.requiredVersion)
279                 dataObject.apiVersion = config.requiredVersion;
280 
281             if (config.includeStyle)
282                 dataObject.includeStyle = config.includeStyle;
283 
284             var qsParams = {};
285             if (config.sort)
286                 qsParams["query.sort"] = config.sort;
287 
288             if (config.parameters)
289             {
290                 for (var n in config.parameters)
291                 {
292                     if (config.parameters.hasOwnProperty(n))
293                     {
294                         qsParams["query.param." + n] = config.parameters[n];
295                     }
296                 }
297             }
298 
299             var requestConfig = {
300                 url : LABKEY.ActionURL.buildURL("query", "executeSql.api", config.containerPath, qsParams),
301                 method : 'POST',
302                 success: getSuccessCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.stripHiddenColumns, config.scope, config.requiredVersion),
303                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
304                 jsonData : dataObject,
305                 headers : {
306                     'Content-Type' : 'application/json'
307                 }
308             };
309 
310             if (LABKEY.Utils.isDefined(config.timeout))
311                 requestConfig.timeout = config.timeout;
312 
313             return LABKEY.Ajax.request(requestConfig);
314         },
315 
316         /**
317          * Bulk import data rows into a table.
318          * One of 'text', 'path', 'moduleResource', or 'file' is required and cannot be combined.
319          *
320          * @param {Object} config An object which contains the following configuration properties.
321          * @param {String} config.schemaName Name of a schema defined within the current container.
322          * @param {String} config.queryName Name of a query table associated with the chosen schema.
323          * @param {File} [config.file] A <a href='https://developer.mozilla.org/en-US/docs/DOM/File'><code>File</code></a> object or a file input element to upload to the server.
324          * @param {String} [config.text] Text to import.
325          * @param {String} [config.path] Path to resource under webdav tree. E.g. "/_webdav/MyProject/@files/data.tsv"
326          * @param {String} [config.module] Module name to use when resolving a module resource.
327          * @param {String} [config.moduleResource] A file resource within the module to import.
328          * @param {String} [config.importIdentity] When true, auto-increment key columns may be imported from the data.
329          * @param {String} [config.importLookupByAlternateKey] When true, lookup columns can be imported by their alternate keys instead of the primary key.
330          *          For example, if a column is a lookup to a SampleSet, the imported value can be the Sample's name since names must be unique within a SampleSet.
331          * @param {Function} [config.success] Function called when the "importData" function executes successfully.
332                         Will be called with the following arguments:
333                         An object containing success and rowCount properties.
334          * @param {Function} [config.failure]  Function called importing data fails.
335          * @param {String} [config.containerPath] The container path in which the schema and query name are defined.
336          * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
337          *       generating a timeout error (defaults to 30000).
338          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
339          * @returns {Mixed} In client-side scripts, this method will return a transaction id
340          * for the async request that can be used to cancel the request
341          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
342          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
343          * @example Example, importing tsv data from a module: <pre name="code" class="javascript">
344          LABKEY.Query.importData({
345                  schemaName: 'lists',
346                  queryName: 'People',
347                  // reference to <input type='file' id='file'>
348                  file: document.getElementById('file')
349              },
350          });</pre>
351          * @example Example, importing tsv data from a module: <pre name="code" class="javascript">
352          LABKEY.Query.importData({
353                  schemaName: 'lists',
354                  queryName: 'People',
355                  module: 'mymodule',
356                  moduleResource: '/data/lists/People.tsv'
357              },
358          });</pre>
359         */
360         importData : function (config)
361         {
362             if (!window.FormData)
363                 throw new Error("modern browser required");
364 
365             var form = new FormData();
366 
367             form.append("schemaName", config.schemaName);
368             form.append("queryName", config.queryName);
369             if (config.text)
370                 form.append("text", config.text);
371             if (config.path)
372                 form.append("path", config.path);
373             if (config.format)
374                 form.append("format", config.format);
375             if (config.module)
376                 form.append("module", config.module);
377             if (config.moduleResource)
378                 form.append("moduleResource", config.moduleResource);
379             if (config.importIdentity)
380                 form.append("importIdentity", config.importIdentity);
381             if (config.importLookupByAlternateKey)
382                 form.append("importLookupByAlternateKey", config.importLookupByAlternateKey);
383 
384             if (config.file) {
385                 if (config.file instanceof File)
386                     form.append("file", config.file);
387                 else if (config.file.tagName == "INPUT" && config.file.files.length > 0)
388                     form.append("file", config.file.files[0]);
389             }
390 
391             return LABKEY.Ajax.request({
392                 url: LABKEY.ActionURL.buildURL("query", "import.api", config.containerPath),
393                 method: 'POST',
394                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope, false),
395                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
396                 form: form,
397                 timeout: config.timeout
398             });
399         },
400 
401         /**
402         * Select rows.
403         * @param {Object} config An object which contains the following configuration properties.
404         * @param {String} config.schemaName Name of a schema defined within the current container. See also: <a class="link"
405 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
406 					How To Find schemaName, queryName & viewName</a>.
407         * @param {String} config.queryName Name of a query table associated with the chosen schema. See also: <a class="link"
408 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
409 					How To Find schemaName, queryName & viewName</a>.
410         * @param {Function} config.success
411 				Function called when the "selectRows" function executes successfully.
412 				This function will be called with the following arguments:
413 				<ul>
414 				    <li>
415                         <b>data:</b> If config.requiredVersion is not set, or set to "8.3", the success handler will be
416                         passed a {@link LABKEY.Query.SelectRowsResults} object. If set to "9.1" the success handler will
417                         be passed a {@link LABKEY.Query.ExtendedSelectRowsResults} object. If set to "13.2" the succes
418                         handler will be passed a {@link LABKEY.Query.Response} object.
419                     </li>
420                     <li><b>responseObj:</b> The XMLHttpResponseObject instance used to make the AJAX request</li>
421 				    <li><b>options:</b> The options used for the AJAX request</li>
422 				</ul>
423         * @param {Function} [config.failure] Function called when execution of the "selectRows" function fails.
424         *       This function will be called with the following arguments:
425 				<ul>
426 				    <li><b>errorInfo:</b> an object describing the error with the following fields:
427                         <ul>
428                             <li><b>exception:</b> the exception message</li>
429                             <li><b>exceptionClass:</b> the Java class of the exception thrown on the server</li>
430                             <li><b>stackTrace:</b> the Java stack trace at the point when the exception occurred</li>
431                         </ul>
432                     </li>
433                     <li><b>responseObj:</b> the XMLHttpResponseObject instance used to make the AJAX request</li>
434 				    <li><b>options:</b> the options used for the AJAX request</li>
435 				</ul>
436         * @param {Array} [config.filterArray] Array of objects created by {@link LABKEY.Filter.create}.
437         * @param {Object} [config.parameters] Map of name (string)/value pairs for the values of parameters if the SQL
438         *        references underlying queries that are parameterized. For example, the following passes two parameters to the query: {'Gender': 'M', 'CD4': '400'}.
439         *        The parameters are written to the request URL as follows: query.param.Gender=M&query.param.CD4=400.  For details on parameterized SQL queries, see
440         *        <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=paramsql">Parameterized SQL Queries</a>.
441         * @param {String} [config.sort]  String description of the sort.  It includes the column names
442         *       listed in the URL of a sorted data region (with an optional minus prefix to indicate
443         *       descending order). In the case of a multi-column sort, up to three column names can be
444         *       included, separated by commas.
445         * @param {String} [config.viewName] The name of a custom view saved on the server for the specified query.
446         * @param {String} [config.columns] An Array of columns or a comma-delimited list of column names you wish to select from the specified
447         *       query. By default, selectRows will return the set of columns defined in the default value for this query,
448         *       as defined via the Customize View user interface on the server. You can override this by specifying a list
449         *       of column names in this parameter, separated by commas. The names can also include references to related
450         *       tables (e.g., 'RelatedPeptide/Peptide' where 'RelatedPeptide is the name of a foreign key column in the
451         *       base query, and 'Peptide' is the name of a column in the related table).
452         * @param {String} [config.containerPath] The path to the container in which the schema and query are defined,
453         *       if different than the current container. If not supplied, the current container's path will be used.
454          * @param {String} [config.containerFilter] One of the values of {@link LABKEY.Query.containerFilter} that sets
455          *       the scope of this query. Defaults to containerFilter.current, and is interpreted relative to
456          *       config.containerPath.
457         * @param {String} [config.showRows] Either 'paginated' (the default) 'selected', 'unselected', 'all', or 'none'.
458         *        When 'paginated', the maxRows and offset parameters can be used to page through the query's result set rows.
459         *        When 'selected' or 'unselected' the set of rows selected or unselected by the user in the grid view will be returned.
460         *        You can programatically get and set the selection using the {@link LABKEY.DataRegion.setSelected} APIs.
461         *        Setting <code>config.maxRows</code> to -1 is the same as 'all'
462         *        and setting <code>config.maxRows</code> to 0 is the same as 'none'.
463         * @param {Integer} [config.maxRows] The maximum number of rows to return from the server (defaults to 100000).
464         *        If you want to return all possible rows, set this config property to -1.
465         * @param {Integer} [config.offset] The index of the first row to return from the server (defaults to 0).
466         *        Use this along with the maxRows config property to request pages of data.
467         * @param {Boolean} [config.includeTotalCount] Include the total number of rows available (defaults to true).
468         *       If false totalCount will equal number of rows returned (equal to maxRows unless maxRows == 0).
469         * @param {Boolean} [config.includeDetailsColumn] Include the Details link column in the set of columns (defaults to false).
470         *       If included, the column will have the name "~~Details~~". The underlying table/query must support details links
471         *       or the column will be omitted in the response.
472         * @param {Boolean} [config.includeUpdateColumn] Include the Update (or edit) link column in the set of columns (defaults to false).
473         *       If included, the column will have the name "~~Update~~". The underlying table/query must support update links
474         *       or the column will be omitted in the response.
475         * @param {String} [config.selectionKey] Unique string used by selection APIs as a key when storing or retrieving the selected items for a grid.
476         *         Not used unless <code>config.showRows</code> is 'selected' or 'unselected'.
477         * @param {Boolean} [config.ignoreFilter] If true, the command will ignore any filter that may be part of the chosen view.
478         * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
479         *       generating a timeout error (defaults to 30000).
480         * @param {Double} [config.requiredVersion] If not set, or set to "8.3", the success handler will be passed a {@link LABKEY.Query.SelectRowsResults}
481                 object. If set to "9.1" the success handler will be passed a {@link LABKEY.Query.ExtendedSelectRowsResults}
482                 object. If set to "13.2" the success handler will be passed a {@link LABKEY.Query.Response} object.
483                 The main difference between SelectRowsResults and ExtendedSelectRowsResults is that each column in each row
484                 will be another object (not just a scalar value) with a "value" property as well as other related properties
485                 (url, mvValue, mvIndicator, etc.). In the LABKEY.Query.Response format each row will an instance of
486                 {@link LABKEY.Query.Row}.
487         * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
488          * @returns {Mixed} In client-side scripts, this method will return a transaction id
489          * for the async request that can be used to cancel the request
490          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
491          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
492         * @example Example: <pre name="code" class="xml">
493 <script type="text/javascript">
494 	function onFailure(errorInfo, options, responseObj)
495 	{
496 	    if (errorInfo && errorInfo.exception)
497 	        alert("Failure: " + errorInfo.exception);
498 	    else
499 	        alert("Failure: " + responseObj.statusText);
500 	}
501 
502 	function onSuccess(data)
503 	{
504 	    alert("Success! " + data.rowCount + " rows returned.");
505 	}
506 
507 	LABKEY.Query.selectRows({
508             schemaName: 'lists',
509             queryName: 'People',
510             columns: ['Name', 'Age'],
511             success: onSuccess,
512             failure: onFailure
513         });
514 </script> </pre>
515 		* @see LABKEY.Query.SelectRowsOptions
516 		* @see LABKEY.Query.SelectRowsResults
517         * @see LABKEY.Query.ExtendedSelectRowsResults
518         * @see LABKEY.Query.Response
519 		*/
520         selectRows : function(config)
521         {
522             //check for old-style separate arguments
523             if (arguments.length > 1)
524             {
525                 config = {
526                     schemaName: arguments[0],
527                     queryName: arguments[1],
528                     success: arguments[2],
529                     errorCallback: arguments[3],
530                     filterArray: arguments[4],
531                     sort: arguments[5],
532                     viewName: arguments[6]
533                 };
534             }
535 
536             if (!config.schemaName)
537                 throw "You must specify a schemaName!";
538             if (!config.queryName)
539                 throw "You must specify a queryName!";
540 
541             config.dataRegionName = config.dataRegionName || "query";
542 
543             var dataObject = LABKEY.Query.buildQueryParams(
544                     config.schemaName,
545                     config.queryName,
546                     config.filterArray,
547                     config.sort,
548                     config.dataRegionName
549             );
550 
551             if (!config.showRows || config.showRows == 'paginated')
552             {
553                 if (config.offset)
554                     dataObject[config.dataRegionName + '.offset'] = config.offset;
555 
556                 if (config.maxRows != undefined)
557                 {
558                     if (config.maxRows < 0)
559                         dataObject[config.dataRegionName + '.showRows'] = "all";
560                     else
561                         dataObject[config.dataRegionName + '.maxRows'] = config.maxRows;
562                 }
563             }
564             else if (config.showRows in {'all':true, 'selected':true, 'unselected':true, 'none':true})
565             {
566                 dataObject[config.dataRegionName + '.showRows'] = config.showRows;
567             }
568 
569 
570             if (config.viewName)
571                 dataObject[config.dataRegionName + '.viewName'] = config.viewName;
572 
573             if (config.columns)
574                 dataObject[config.dataRegionName + '.columns'] = LABKEY.Utils.isArray(config.columns) ? config.columns.join(",") : config.columns;
575 
576             if (config.selectionKey)
577                 dataObject[config.dataRegionName + '.selectionKey'] = config.selectionKey;
578 
579             if (config.ignoreFilter)
580                 dataObject[config.dataRegionName + '.ignoreFilter'] = 1;
581 
582             if (config.parameters)
583             {
584                 for (var propName in config.parameters)
585                 {
586                     if (config.parameters.hasOwnProperty(propName))
587                         dataObject[config.dataRegionName + '.param.' + propName] = config.parameters[propName];
588                 }
589             }
590 
591             if (config.requiredVersion)
592                 dataObject.apiVersion = config.requiredVersion;
593 
594             if (config.containerFilter)
595                 dataObject.containerFilter = config.containerFilter;
596 
597             if (config.includeTotalCount)
598                 dataObject.includeTotalCount = config.includeTotalCount;
599 
600             if (config.includeDetailsColumn)
601                 dataObject.includeDetailsColumn = config.includeDetailsColumn;
602 
603             if (config.includeUpdateColumn)
604                 dataObject.includeUpdateColumn = config.includeUpdateColumn;
605 
606             if (config.includeStyle)
607                 dataObject.includeStyle = config.includeStyle;
608 
609             var requestConfig = {
610                 url : LABKEY.ActionURL.buildURL('query', 'getQuery.api', config.containerPath),
611                 method : getMethod(config.method),
612                 success: getSuccessCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.stripHiddenColumns, config.scope, config.requiredVersion),
613                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
614                 params : dataObject
615             };
616 
617             if (LABKEY.Utils.isDefined(config.timeout))
618                 requestConfig.timeout = config.timeout;
619 
620             return LABKEY.Ajax.request(requestConfig);
621         },
622 
623         /**
624          * Select Distinct Rows
625          * @param {Object} config An object which contains the following configuration properties.
626          * @param {String} config.schemaName Name of a schema defined within the current container. See also: <a class="link"
627                         href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
628                         How To Find schemaName, queryName & viewName</a>.
629          * @param {String} config.queryName Name of a query table associated with the chosen schema.  See also: <a class="link"
630                         href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
631                         How To Find schemaName, queryName & viewName</a>.
632          * @param {String} config.column A single column for which the distinct results will be requested. This column
633          *              must exist within the specified query.
634          * @param {String} [config.containerFilter] One of the values of {@link LABKEY.Query.containerFilter} that sets
635          *       the scope of this query. Defaults to containerFilter.current, and is interpreted relative to
636          *       config.containerPath.
637          * @param {Object} [config.parameters] Map of name (string)/value pairs for the values of parameters if the SQL
638          *        references underlying queries that are parameterized. For example, the following passes two parameters to the query: {'Gender': 'M', 'CD4': '400'}.
639          *        The parameters are written to the request URL as follows: query.param.Gender=M&query.param.CD4=400.  For details on parameterized SQL queries, see
640          *        <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=paramsql">Parameterized SQL Queries</a>.
641          * @param {Array} [config.filterArray] Array of objects created by {@link LABKEY.Filter.create}.
642          * @param {String} [config.viewName] Name of a view to use.  This is potentially important if this view contains filters on the data.
643          * @param {Function} config.success
644          * @param {Function} config.failure
645          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
646          */
647         selectDistinctRows : function(config)
648         {
649             if (!config.schemaName)
650                 throw "You must specify a schemaName!";
651             if (!config.queryName)
652                 throw "You must specify a queryName!";
653             if (!config.column)
654                 throw "You must specify a column!";
655 
656             config.dataRegionName = config.dataRegionName || "query";
657 
658             var dataObject = LABKEY.Query.buildQueryParams(
659                     config.schemaName,
660                     config.queryName,
661                     config.filterArray,
662                     config.sort,
663                     config.dataRegionName
664             );
665 
666             dataObject[config.dataRegionName + '.columns'] = config.column;
667 
668             if (config.viewName)
669                 dataObject[config.dataRegionName + '.viewName'] = config.viewName;
670 
671             if (config.maxRows && config.maxRows >= 0)
672                 dataObject.maxRows = config.maxRows;
673 
674             if (config.containerFilter)
675                 dataObject.containerFilter = config.containerFilter;
676 
677             if (config.parameters)
678             {
679                 for (var propName in config.parameters)
680                 {
681                     if (config.parameters.hasOwnProperty(propName))
682                         dataObject[config.dataRegionName + '.param.' + propName] = config.parameters[propName];
683                 }
684             }
685 
686             if (config.ignoreFilter)
687             {
688                 dataObject[config.dataRegionName + '.ignoreFilter'] = true;
689             }
690 
691             return LABKEY.Ajax.request({
692                 url : LABKEY.ActionURL.buildURL('query', 'selectDistinct.api', config.containerPath),
693                 method : getMethod(config.method),
694                 success: getSuccessCallbackWrapper(LABKEY.Utils.getOnSuccess(config), false, config.scope),
695                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
696                 params : dataObject
697             });
698         },
699 
700 
701         /**
702          * Returns a list of reports, views and/or datasets in a container
703          * @param config
704          * @param {String} [config.containerPath] A container path in which to execute this command.  If not provided, the current container will be used
705          * @param {Array} [config.dataTypes] An array of data types to return, which can be any of: 'reports', 'datasets' or 'queries'.  If null, all will be returned
706          * @param {Function} [config.success] A function called on success.  It will be passed a single argument with the following properties:
707          * <ul>
708          * <li>data: An array with one element per dataview.  Each view is a map with the following properties:
709          * <ul>
710          * <li>access:
711          * <li>allowCustomThumbnail: A flag indicating whether the thumbnail can be customized
712          * <li>category: The category to which this item has been assigned
713          * <li>categoryDisplayOrder: The display order within that category
714          * <li>container: The container where this dataView is defined
715          * <li>created: The displayName of the user who created the item
716          * <li>createdByUserId: The user Id of the user who created the item
717          * <li>dataType: The dataType of this item, either queries, reports or datasets
718          * <li>detailsUrl: The url that will display additional details about this item
719          * <li>icon: The url of the icon for this report
720          * <li>id: The unique Id of this item
721          * <li>reportId: The unique report Id if this item is a report. Value is null if this item is not a report.
722          * <li>modified: The date this item was last modified
723          * <li>name: The display name of this item
724          * <li>runUrl: The url that can be used to execute this report
725          * <li>shared: A flag indicating whether this item is shared
726          * <li>thumbnail: The url of this item's thumbnail image
727          * <li>type: The display string for the Data Type.
728          * <li>visible: A flag indicating whether this report is visible or hidden
729          * </ul>
730          * <li>types: a map of each dataType, and a boolean indicating whether it was included in the results (this is based on the dataTypes param in the config)
731          * </ul>
732          * @param {Function} [config.failure] A function called when execution of "getDataViews" fails.
733          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
734          */
735         getDataViews : function(config)
736         {
737             var dataObject = {
738                 includeData: true,
739                 includeMetadata: false
740             };
741             if(config.dataTypes)
742                 dataObject.dataTypes = config.dataTypes;
743 
744             var callbackFn = LABKEY.Utils.getOnSuccess(config);
745             var success = LABKEY.Utils.getCallbackWrapper(function(data, response, options){
746                                             if (callbackFn)
747                                                 callbackFn.call(config.scope || this, data.data, options, response);
748                                         }, this);
749 
750             return LABKEY.Ajax.request({
751                 url : LABKEY.ActionURL.buildURL('reports', 'browseData.api', config.containerPath),
752                 method : 'POST',
753                 success: success,
754                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
755                 jsonData : dataObject,
756                 headers : {
757                     'Content-Type' : 'application/json'
758                 }
759             });
760         },
761 
762         /**
763         * Update rows.
764         * @param {Object} config An object which contains the following configuration properties.
765         * @param {String} config.schemaName Name of a schema defined within the current container. See also: <a class="link"
766 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
767 					How To Find schemaName, queryName & viewName</a>.
768         * @param {String} config.queryName Name of a query table associated with the chosen schema.  See also: <a class="link"
769 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
770 					How To Find schemaName, queryName & viewName</a>.
771         * @param {Array} config.rows Array of record objects in which each object has a property for each field.
772         *               The row array must include the primary key column values and values for
773         *               other columns you wish to update.
774         * @param {Object} [config.extraContext] <b>Experimental:</b> Optional extra context object passed into the transformation/validation script environment.
775         * @param {Function} config.success Function called when the "updateRows" function executes successfully.
776         	    Will be called with arguments:
777                 the parsed response data ({@link LABKEY.Query.ModifyRowsResults}), the XMLHttpRequest object and
778                 (optionally) the "options" object ({@link LABKEY.Query.ModifyRowsOptions}).
779         * @param {Function} [config.failure] Function called when execution of the "updateRows" function fails.
780         *                   See {@link LABKEY.Query.selectRows} for more information on the parameters passed to this function.
781         * @param {String} [config.containerPath] The container path in which the schema and query name are defined.
782         *              If not supplied, the current container path will be used.
783         * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
784         *       generating a timeout error (defaults to 30000).
785         * @param {boolean} [config.transacted] Whether all of the updates should be done in a single transaction, so they all succeed or all fail. Defaults to true
786         * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
787          * @returns {Mixed} In client-side scripts, this method will return a transaction id
788          * for the async request that can be used to cancel the request
789          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
790          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
791 		* @see LABKEY.Query.ModifyRowsResults
792 		* @see LABKEY.Query.ModifyRowsOptions
793         */
794         updateRows : function(config)
795         {
796             if (arguments.length > 1)
797                 config = configFromArgs(arguments);
798             config.action = "updateRows.api";
799             return sendJsonQueryRequest(config);
800         },
801 
802         /**
803         * Save inserts, updates, and/or deletes to potentially multiple tables with a single request.
804         * @param {Object} config An object which contains the following configuration properties.
805         * @param {Array} config.commands An array of all of the update/insert/delete operations to be performed.
806         * Each command has the following structure:
807         * @param {String} config.commands[].schemaName Name of a schema defined within the current container. See also: <a class="link"
808 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
809 					How To Find schemaName, queryName & viewName</a>.
810         * @param {String} config.commands[].queryName Name of a query table associated with the chosen schema.  See also: <a class="link"
811 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
812 					How To Find schemaName, queryName & viewName</a>.
813         * @param {String} config.commands[].command Name of the command to be performed. Must be one of "insert", "update", or "delete".
814         * @param {Array} config.commands[].rows An array of data for each row to be changed. See {@link LABKEY.Query.insertRows},
815         * {@link LABKEY.Query.updateRows}, or {@link LABKEY.Query.deleteRows} for requirements of what data must be included for each row.
816         * @param {Object} [config.commands[].extraContext] <b>Experimental:</b> Optional extra context object passed into the transformation/validation script environment.
817         * @param {Object} [config.extraContext] <b>Experimental:</b> Optional extra context object passed into the transformation/validation script environment.
818         * The extraContext at the command-level will be merged with the extraContext at the top-level of the config.
819         * @param {Function} config.success Function called when the "saveRows" function executes successfully.
820         	    Called with arguments:
821                 <ul>
822                     <li>an object with the following properties:
823                     <ul>
824                         <li><strong>result</strong>: an array of parsed response data ({@link LABKEY.Query.ModifyRowsResults}) (one for each command in the request)
825                         <li><strong>errorCount</strong>: an integer, with the total number of errors encountered during the operation
826                         <li><strong>committed</strong>: a boolean, indicating if the changes were actually committed to the database
827                     </ul>
828                     <li>the XMLHttpRequest object</li>
829                     <li>(optionally) the "options" object ({@link LABKEY.Query.ModifyRowsOptions})</li>
830                 </ul>
831         * @param {Function} [config.failure] Function called if execution of the "saveRows" function fails.
832         *                   See {@link LABKEY.Query.selectRows} for more information on the parameters passed to this function.
833         * @param {String} [config.containerPath] The container path in which the changes are to be performed.
834         *              If not supplied, the current container path will be used.
835         * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
836         *       generating a timeout error (defaults to 30000).
837         * @param {Double} [config.apiVersion] Version of the API. If this is 13.2 or higher, a request that fails
838         * validation will be returned as a successful response. Use the 'errorCount' and 'committed' properties in the
839         * response to tell if it committed or not. If this is 13.1 or lower (or unspecified), the failure callback
840         * will be invoked instead in the event of a validation failure.
841         * @param {boolean} [config.transacted] Whether all of the row changes for all of the tables
842         * should be done in a single transaction, so they all succeed or all fail. Defaults to true
843         * @param {boolean} [config.validateOnly] Whether or not the server should attempt proceed through all of the
844         * commands, but not actually commit them to the database. Useful for scenarios like giving incremental
845         * validation feedback as a user fills out a UI form, but not actually save anything until they explicitly request
846         * a save.
847         * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
848          * @returns {Mixed} In client-side scripts, this method will return a transaction id
849          * for the async request that can be used to cancel the request
850          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
851          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
852 		* @see LABKEY.Query.ModifyRowsResults
853 		* @see LABKEY.Query.ModifyRowsOptions
854         */
855         saveRows : function(config)
856         {
857             if (arguments.length > 1)
858                 config = configFromArgs(arguments);
859 
860             var dataObject = {
861                 commands: config.commands,
862                 containerPath: config.containerPath,
863                 validateOnly : config.validateOnly,
864                 transacted : config.transacted,
865                 extraContext : config.extraContext,
866                 apiVersion : config.apiVersion
867             };
868 
869             var requestConfig = {
870                 url : LABKEY.ActionURL.buildURL("query", "saveRows.api", config.containerPath),
871                 method : 'POST',
872                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
873                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
874                 jsonData : dataObject,
875                 headers : {
876                     'Content-Type' : 'application/json'
877                 }
878             };
879 
880             if (LABKEY.Utils.isDefined(config.timeout))
881                 requestConfig.timeout = config.timeout;
882 
883             return LABKEY.Ajax.request(requestConfig);
884 
885         },
886 
887         /**
888         * Insert rows.
889         * @param {Object} config An object which contains the following configuration properties.
890         * @param {String} config.schemaName Name of a schema defined within the current container.  See also: <a class="link"
891 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
892 					How To Find schemaName, queryName & viewName</a>.
893         * @param {String} config.queryName Name of a query table associated with the chosen schema. See also: <a class="link"
894 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
895 					How To Find schemaName, queryName & viewName</a>.
896         * @param {Array} config.rows Array of record objects in which each object has a property for each field.
897         *                  The row data array must include all column values except for the primary key column.
898         *                  However, you will need to include the primary key column values if you defined
899         *                  them yourself instead of relying on auto-number.
900         * @param {Object} [config.extraContext] <b>Experimental:</b> Optional extra context object passed into the transformation/validation script environment.
901         * @param {Function} config.success Function called when the "insertRows" function executes successfully.
902 						Will be called with the following arguments:
903                         the parsed response data ({@link LABKEY.Query.ModifyRowsResults}), the XMLHttpRequest object and
904                         (optionally) the "options" object ({@link LABKEY.Query.ModifyRowsOptions}).
905 		* @param {Function} [config.failure]  Function called when execution of the "insertRows" function fails.
906         *                   See {@link LABKEY.Query.selectRows} for more information on the parameters passed to this function.
907         * @param {String} [config.containerPath] The container path in which the schema and query name are defined.
908         *              If not supplied, the current container path will be used.
909         * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
910         *       generating a timeout error (defaults to 30000).
911         * @param {boolean} [config.transacted] Whether all of the inserts should be done in a single transaction, so they all succeed or all fail. Defaults to true
912         * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
913          * @returns {Mixed} In client-side scripts, this method will return a transaction id
914          * for the async request that can be used to cancel the request
915          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
916          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
917         * @example Example, from the Reagent Request <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=reagentRequestForm">Tutorial</a> and <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a>: <pre name="code" class="xml">
918          // This snippet inserts data from the ReagentReqForm into a list.
919          // Upon success, it moves the user to the confirmation page and
920          // passes the current user's ID to that page.
921          LABKEY.Query.insertRows({
922              containerPath: '/home/Study/demo/guestaccess',
923              schemaName: 'lists',
924              queryName: 'Reagent Requests',
925              rows: [{
926                 "Name":  ReagentReqForm.DisplayName.value,
927                 "Email": ReagentReqForm.Email.value,
928                 "UserID": ReagentReqForm.UserID.value,
929                 "Reagent": ReagentReqForm.Reagent.value,
930                 "Quantity": parseInt(ReagentReqForm.Quantity.value),
931                 "Date": new Date(),
932                 "Comments": ReagentReqForm.Comments.value,
933                 "Fulfilled": 'false'
934              }],
935              successCallback: function(data){
936                  window.location =
937                     '/wiki/home/Study/demo/page.view?name=confirmation&userid='
938                     + LABKEY.Security.currentUser.id;
939              },
940          });  </pre>
941 		* @see LABKEY.Query.ModifyRowsResults
942 		* @see LABKEY.Query.ModifyRowsOptions
943         */
944         insertRows : function(config)
945         {
946             if (arguments.length > 1)
947                 config = configFromArgs(arguments);
948             config.action = "insertRows.api";
949             return sendJsonQueryRequest(config);
950         },
951 
952         /**
953         * Delete rows.
954         * @param {Object} config An object which contains the following configuration properties.
955         * @param {String} config.schemaName Name of a schema defined within the current container. See also: <a class="link"
956 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
957 					How To Find schemaName, queryName & viewName</a>.
958         * @param {String} config.queryName Name of a query table associated with the chosen schema. See also: <a class="link"
959 					href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
960 					How To Find schemaName, queryName & viewName</a>.
961         * @param {Object} [config.extraContext] <b>Experimental:</b> Optional extra context object passed into the transformation/validation script environment.
962         * @param {Function} config.success Function called when the "deleteRows" function executes successfully.
963                      Will be called with the following arguments:
964                      the parsed response data ({@link LABKEY.Query.ModifyRowsResults}), the XMLHttpRequest object and
965                      (optionally) the "options" object ({@link LABKEY.Query.ModifyRowsOptions}).
966 		* @param {Function} [config.failure] Function called when execution of the "deleteRows" function fails.
967          *                   See {@link LABKEY.Query.selectRows} for more information on the parameters passed to this function.
968         * @param {Array} config.rows Array of record objects in which each object has a property for each field.
969         *                  The row data array needs to include only the primary key column value, not all columns.
970         * @param {String} [config.containerPath] The container path in which the schema and query name are defined.
971         *              If not supplied, the current container path will be used.
972         * @param {Integer} [config.timeout] The maximum number of milliseconds to allow for this operation before
973         *       generating a timeout error (defaults to 30000).
974         * @param {boolean} [config.transacted] Whether all of the deletes should be done in a single transaction, so they all succeed or all fail. Defaults to true
975         * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
976          * @returns {Mixed} In client-side scripts, this method will return a transaction id
977          * for the async request that can be used to cancel the request
978          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
979          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
980 		* @see LABKEY.Query.ModifyRowsResults
981 		* @see LABKEY.Query.ModifyRowsOptions
982         */
983         deleteRows : function(config)
984         {
985             if (arguments.length > 1)
986             {
987                 config = configFromArgs(arguments);
988             }
989             config.action = "deleteRows.api";
990             return sendJsonQueryRequest(config);
991         },
992 
993         /**
994          * Delete a query view.
995          * @param config An object that contains the following configuration parameters
996          * @param {String} config.schemaName The name of the schema.
997          * @param {String} config.queryName the name of the query.
998          * @param {String} [config.viewName] the name of the view. If a viewName is not specified, the default view will be deleted/reverted.
999          * @param {boolean} [config.revert] Optionally, the view can be reverted instead of deleted. Defaults to false.
1000          */
1001         deleteQueryView : function(config) {
1002             if (!config) {
1003                 throw 'You must specify a configuration!'
1004             }
1005             if (!config.schemaName) {
1006                 throw 'You must specify a schemaName!'
1007             }
1008             if (!config.queryName) {
1009                 throw 'You must specify a queryName!'
1010             }
1011 
1012             var params = {
1013                 schemaName: config.schemaName,
1014                 queryName: config.queryName
1015             };
1016 
1017             if (config.viewName) {
1018                 params.viewName = config.viewName;
1019             }
1020 
1021             if (config.revert !== undefined) {
1022                 params.complete = config.revert !== true;
1023             }
1024 
1025             return LABKEY.Ajax.request({
1026                 url: LABKEY.ActionURL.buildURL('query', 'deleteView.api', config.containerPath),
1027                 method: 'POST',
1028                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1029                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1030                 jsonData: params
1031             });
1032         },
1033 
1034         /**
1035          * Build and return an object suitable for passing to the
1036          * <a href = "http://www.extjs.com/deploy/dev/docs/?class=Ext.Ajax">Ext.Ajax</a> 'params' configuration property.
1037          * @param {string} schemaName Name of a schema defined within the current container.  See also: <a class="link"
1038          href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
1039          How To Find schemaName, queryName & viewName</a>.
1040          * @param {string} queryName Name of a query table associated with the chosen schema.   See also: <a class="link"
1041          href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
1042          How To Find schemaName, queryName & viewName</a>.
1043          * @param {LABKEY.Filter[]} [filterArray] Array of objects created by {@link LABKEY.Filter.create}.
1044          * @param {string} [sort]  String description of the sort.  It includes the column names
1045          *       listed in the URL of a sorted data region (with an optional minus prefix to indicate
1046          *       descending order). In the case of a multi-column sort, up to three column names can be
1047          *       included, separated by commas.
1048          * @param {string} [dataRegionName=query]
1049          * @returns {Object} Object suitable for passing to the
1050          * <a href = "http://extjs.com/deploy/ext-2.2.1/docs/?class=Ext.Ajax">Ext.Ajax</a> 'params' configuration property.
1051          */
1052         buildQueryParams: function(schemaName, queryName, filterArray, sort, dataRegionName)
1053         {
1054             dataRegionName = dataRegionName || "query";
1055             var params = {};
1056             params.dataRegionName = dataRegionName;
1057             params[dataRegionName + '.queryName'] = queryName;
1058             params.schemaName = schemaName;
1059             if (sort)
1060             {
1061                 params[dataRegionName + '.sort'] = sort;
1062             }
1063 
1064             LABKEY.Filter.appendFilterParams(params, filterArray, dataRegionName);
1065 
1066             return params;
1067         },
1068 
1069         /**
1070          * Returns the set of schemas available in the specified container.
1071          * @param config An object that contains the following configuration parameters
1072          * @param {String} config.schemaName Get schemas under the given schemaName.
1073          * @param {String} config.apiVersion Version of the API. Changed the structure of the server's response.
1074          * @param {function} config.success The function to call when the function finishes successfully.
1075          * This function will be called with the following parameters:
1076          * <ul>
1077          * <li><b>schemasInfo:</b> An object with a property called "schemas". If no apiVersion is specified, or it is
1078          * less than 9.3, it will be an array of schema names. If apiVersion is 9.3 or greater, it will be a map where
1079          * the keys are schemaNames and the values are objects with the following properties:
1080          *     <ul>
1081          *         <li><b>schemaName</b>: the short name of the schema</li>
1082          *         <li><b>fullyQualifiedName</b>: the fully qualified name of the schema, encoded as a string with
1083          *         "." separators as described in {@link LABKEY.SchemaKey}</li>
1084          *         <li><b>description</b>: a short description of the schema</li>
1085          *         <li><b>schemas</b>: a map of child schemas, with values in the same structure as this object</li>
1086          *     </ul>
1087          * </li>
1088          * </ul>
1089          * @param {function} [config.failure] The function to call if this function encounters an error.
1090          * This function will be called with the following parameters:
1091          * <ul>
1092          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1093          * </ul>
1094          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1095          * the current container will be used.
1096          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1097          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1098          * for the async request that can be used to cancel the request
1099          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1100          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1101          */
1102         getSchemas : function(config)
1103         {
1104             var params = {};
1105             if (config.apiVersion)
1106                 params.apiVersion = config.apiVersion;
1107             if (config.schemaName)
1108                 params.schemaName = config.schemaName;
1109 
1110             return LABKEY.Ajax.request({
1111                 url : LABKEY.ActionURL.buildURL('query', 'getSchemas.api', config.containerPath),
1112                 method : 'GET',
1113                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1114                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1115                 params: params
1116             });
1117         },
1118 
1119         /**
1120          * Returns the set of queries available in a given schema.
1121          * @param config An object that contains the following configuration parameters
1122          * @param {String} config.schemaName The name of the schema.
1123          * @param {function} config.success The function to call when the function finishes successfully.
1124          * This function will be called with the following parameters:
1125          * <ul>
1126          * <li><b>queriesInfo:</b> An object with the following properties
1127          *  <ul>
1128          *      <li><b>schemaName:</b> the name of the requested schema</li>
1129          *      <li><b>queries:</b> an array of objects, each of which has the following properties
1130          *          <ul>
1131          *              <li><b>name:</b> the name of the query</li>
1132          *              <li><b>title:</b> this is the label used when displaying this table. If the table has no title, this will be the same as the name.</li>
1133          *              <li><b>hidden:</b> true if this is a hidden query or table.
1134          *              <li><b>inherit:</b> true if this query is marked as inheritable in sub-folders.
1135          *              <li><b>isUserDefined:</b> true if this is a user-defined query</li>
1136          *              <li><b>canEdit:</b> true if the current user can edit this query</li>
1137          *              <li><b>isMetadataOverrideable:</b> true if the current user may override the query's metadata</li>
1138          *              <li><b>moduleName:</b> the module that defines this query</li>
1139          *              <li><b>isInherited:</b> true if this query is defined in a different container.</li>
1140          *              <li><b>containerPath:</b> if <code>isInherited</code>, the container path where this query is defined.</li>
1141          *              <li><b>description:</b> A description for this query (if provided)</li>
1142          *              <li><b>viewDataUrl:</b> the server-relative URL where this query's data can be viewed.
1143          *                  Available in LabKey Server version 10.2 and later.</li>
1144          *              <li><b>columns:</b> if config.includeColumns is not false, this will contain an array of
1145          *                 objects with the following properties
1146          *                  <ul>
1147          *                      <li><b>name:</b> the name of the column</li>
1148          *                      <li><b>caption:</b> the caption of the column (may be undefined)</li>
1149          *                      <li><b>description:</b> the description of the column (may be undefined)</li>
1150          *                  </ul>
1151          *              </li>
1152          *          </ul>
1153          *      </li>
1154          *  </ul>
1155          * </li>
1156          * </ul>
1157          * @param {function} [config.failure] The function to call if this function encounters an error.
1158          * This function will be called with the following parameters:
1159          * <ul>
1160          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1161          * </ul>
1162          * @param {Boolean} [config.includeUserQueries] If set to false, user-defined queries will not be included in
1163          * the results. Default is true.
1164          * @param {Boolean} [config.includeSystemQueries] If set to false, system-defined queries will not be included in
1165          * the results. Default is true.
1166          * @param {Boolean} [config.includeColumns] If set to false, information about the available columns in this
1167          * query will not be included in the results. Default is true.
1168          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1169          * the current container will be used.
1170          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1171          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1172          * for the async request that can be used to cancel the request
1173          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1174          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1175          */
1176         getQueries : function(config)
1177         {
1178             var params = {};
1179             // Only pass the parameters that the server supports, and exclude ones like successCallback
1180             LABKEY.Utils.applyTranslated(params, config,
1181             {
1182                 schemaName: 'schemaName',
1183                 includeColumns: 'includeColumns',
1184                 includeUserQueries: 'includeUserQueries',
1185                 includeSystemQueries: 'includeSystemQueries'
1186             }, false, false);
1187 
1188             return LABKEY.Ajax.request({
1189                 url: LABKEY.ActionURL.buildURL('query', 'getQueries.api', config.containerPath),
1190                 method : 'GET',
1191                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1192                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1193                 params: params
1194             });
1195         },
1196 
1197         /**
1198          * Returns the set of views available for a given query in a given schema.
1199          * @param config An object that contains the following configuration parameters
1200          * @param {String} config.schemaName The name of the schema.
1201          * @param {String} config.queryName the name of the query.
1202          * @param {String} [config.viewName] A view name (empty string for the default view), otherwise return all views for the query.
1203          * @param {Boolean} [config.metadata] Include view column field metadata.
1204          * @param {function} config.success The function to call when the function finishes successfully.
1205          * This function will be called with the following parameters:
1206          * <ul>
1207          * <li><b>viewsInfo:</b> An object with the following properties
1208          *  <ul>
1209          *      <li><b>schemaName:</b> the name of the requested schema</li>
1210          *      <li><b>queryName:</b> the name of the requested query</li>
1211          *      <li><b>views:</b> an array of objects, each of which has the following properties
1212          *          <ul>
1213          *              <li><b>name:</b> the name of the view (default view's name is empty string)</li>
1214          *              <li><b>label:</b> the label of the view</li>
1215          *              <li><b>default:</b> true if this is the default view info</li>
1216          *              <li><b>viewDataUrl:</b> the server-relative URL where this view's data can be viewed.
1217          *                  Available in LabKey Server version 10.2 and later.</li>
1218          *              <li><b>columns:</b> this will contain an array of objects with the following properties
1219          *                  <ul>
1220          *                      <li><b>name:</b> the name of the column</li>
1221          *                      <li><b>fieldKey:</b> the field key for the column (may include join column names, e.g. 'State/Population')</li>
1222          *                  </ul>
1223          *              </li>
1224          *              <li><b>filter:</b> TBD
1225          *                  Available in LabKey Server version 10.3 and later.</li>
1226          *              <li><b>sort:</b> TBD
1227          *                  Available in LabKey Server version 10.3 and later.</li>
1228          *              <li><b>fields:</b> TBD if metadata
1229          *                  Available in LabKey Server version 10.3 and later.</li>
1230          *          </ul>
1231          *      </li>
1232          *  </ul>
1233          * </li>
1234          * </ul>
1235          * @param {function} [config.failure] The function to call if this function encounters an error.
1236          * This function will be called with the following parameters:
1237          * <ul>
1238          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1239          * </ul>
1240          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1241          * the current container will be used.
1242          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1243          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1244          * for the async request that can be used to cancel the request
1245          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1246          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1247          */
1248         getQueryViews : function(config)
1249         {
1250             var params = {};
1251             if (config.schemaName)
1252                 params.schemaName = config.schemaName;
1253             if (config.queryName)
1254                 params.queryName = config.queryName;
1255             if (config.viewName != undefined)
1256                 params.viewName = config.viewName;
1257             if (config.metadata)
1258                 params.metadata = config.metadata;
1259 
1260             return LABKEY.Ajax.request({
1261                 url: LABKEY.ActionURL.buildURL('query', 'getQueryViews.api', config.containerPath),
1262                 method : 'GET',
1263                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1264                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1265                 params: params
1266             });
1267         },
1268 
1269         /**
1270          * Creates or updates a custom view or views for a given query in a given schema.  The config
1271          * object matches the viewInfos parameter of the getQueryViews.successCallback.
1272          * @param config An object that contains the following configuration parameters
1273          * @param {String} config.schemaName The name of the schema.
1274          * @param {String} config.queryName The name of the query.
1275          * @param {String} config.views The updated view definitions.
1276          * @param {function} config.success The function to call when the function finishes successfully.
1277          * This function will be called with the same parameters as getQueryViews.successCallback.
1278          * @param {function} [config.failure] The function to call if this function encounters an error.
1279          * This function will be called with the following parameters:
1280          * <ul>
1281          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1282          * </ul>
1283          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1284          * the current container will be used.
1285          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1286          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1287          * for the async request that can be used to cancel the request
1288          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1289          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1290          */
1291         saveQueryViews : function (config)
1292         {
1293             var params = {};
1294             if (config.schemaName)
1295                 params.schemaName = config.schemaName;
1296             if (config.queryName)
1297                 params.queryName = config.queryName;
1298             if (config.views)
1299                 params.views = config.views;
1300 
1301             return LABKEY.Ajax.request({
1302                 url: LABKEY.ActionURL.buildURL('query', 'saveQueryViews.api', config.containerPath),
1303                 method: 'POST',
1304                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1305                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1306                 jsonData : params,
1307                 headers : {
1308                     'Content-Type' : 'application/json'
1309                 }
1310             });
1311         },
1312 
1313         /**
1314          * Returns details about a given query including detailed information about result columns
1315          * @param {Object} config An object that contains the following configuration parameters
1316          * @param {String} config.schemaName The name of the schema.
1317          * @param {String} config.queryName The name of the query.
1318          * @param {String} [config.viewName] A view name or Array of view names to include custom view details. Use '*' to include all views for the query.
1319          * @param {String} [config.fields] A field key or Array of field keys to include in the metadata.
1320          * @param {Boolean} [config.initializeMissingView] Initialize the view based on the default view iff the view doesn't yet exist.
1321          * @param {function} config.success The function to call when the function finishes successfully.
1322          * This function will be called with the following parameters:
1323          * <ul>
1324          * <li><b>queryInfo:</b> An object with the following properties
1325          *  <ul>
1326          *      <li><b>schemaName:</b> the name of the requested schema</li>
1327          *      <li><b>name:</b> the name of the requested query</li>
1328          *      <li><b>isUserDefined:</b> true if this is a user-defined query</li>
1329          *      <li><b>canEdit:</b> true if the current user can edit this query</li>
1330          *      <li><b>isMetadataOverrideable:</b> true if the current user may override the query's metadata</li>
1331          *      <li><b>moduleName:</b> the module that defines this query</li>
1332          *      <li><b>isInherited:</b> true if this query is defined in a different container.</li>
1333          *      <li><b>containerPath:</b> if <code>isInherited</code>, the container path where this query is defined.</li>
1334          *      <li><b>viewDataUrl:</b> The URL to navigate to for viewing the data returned from this query</li>
1335          *      <li><b>title:</b> If a value has been set, this is the label used when displaying this table</li>
1336          *      <li><b>description:</b> A description for this query (if provided)</li>
1337          *      <li><b>columns:</b> Information about all columns in this query. This is an array of LABKEY.Query.FieldMetaData objects.</li>
1338          *      <li><b>defaultView:</b> An array of column information for the columns in the current user's default view of this query.
1339          *      The shape of each column info is the same as in the columns array.</li>
1340          *      <li><b>views:</b> An array of view info (XXX: same as views.getQueryViews()
1341          *  </ul>
1342          * </li>
1343          * </ul>
1344          * @see LABKEY.Query.FieldMetaData
1345          * @param {function} [config.failure] The function to call if this function encounters an error.
1346          * This function will be called with the following parameters:
1347          * <ul>
1348          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1349          * </ul>
1350          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1351          * the current container will be used.
1352          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1353          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1354          * for the async request that can be used to cancel the request
1355          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1356          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1357          */
1358         getQueryDetails : function(config)
1359         {
1360             var params = {};
1361             if (config.schemaName)
1362                 params.schemaName = config.schemaName;
1363 
1364             if (config.queryName)
1365                 params.queryName = config.queryName;
1366 
1367             if (config.viewName != undefined)
1368                 params.viewName = config.viewName;
1369 
1370             if (config.fields)
1371                 params.fields = config.fields;
1372 
1373             if (config.fk)
1374                 params.fk = config.fk;
1375 
1376             if (config.initializeMissingView)
1377                 params.initializeMissingView = config.initializeMissingView;
1378 
1379             return LABKEY.Ajax.request({
1380                 url: LABKEY.ActionURL.buildURL('query', 'getQueryDetails.api', config.containerPath),
1381                 method : 'GET',
1382                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1383                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1384                 params: params
1385             });
1386         },
1387 
1388         /**
1389          * Validates the specified query by ensuring that it parses and executes without an exception.
1390          * @param config An object that contains the following configuration parameters
1391          * @param {String} config.schemaName The name of the schema.
1392          * @param {String} config.queryName the name of the query.
1393          * @param {Boolean} config.includeAllColumns If set to false, only the columns in the user's default view
1394          * of the specific query will be tested (defaults to true).
1395          * @param {Boolean} config.validateQueryMetadata If true, the query metadata and custom views will also be validated.
1396          * @param {function} config.success The function to call when the function finishes successfully.
1397          * This function will be called with a simple object with one property named "valid" set to true.
1398          * @param {function} [config.failure] The function to call if this function encounters an error.
1399          * This function will be called with the following parameters:
1400          * <ul>
1401          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message. If validateQueryMetadata was used, this will also hae a property called 'errors', which is an array of objects describing each error.</li>
1402          * </ul>
1403          * @param {String} [config.containerPath] A container path in which to execute this command. If not supplied,
1404          * the current container will be used.
1405          * @param {Object} [config.scope] A scope for the callback functions. Defaults to "this"
1406          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1407          * for the async request that can be used to cancel the request
1408          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1409          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1410          */
1411         validateQuery : function(config)
1412         {
1413             var params = {};
1414 
1415             LABKEY.Utils.applyTranslated(params, config, {
1416                 successCallback: false,
1417                 errorCallback: false,
1418                 scope: false
1419             });
1420 
1421             return LABKEY.Ajax.request({
1422                 url: LABKEY.ActionURL.buildURL('query', (config.validateQueryMetadata ? 'validateQueryMetadata.api' : 'validateQuery.api'), config.containerPath),
1423                 method : 'GET',
1424                 success: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnSuccess(config), config.scope),
1425                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope, true),
1426                 params: params
1427             });
1428         },
1429 
1430         /**
1431          * Returns the current date/time on the LabKey server.
1432          * @param config An object that contains the following configuration parameters
1433          * @param {function} config.success The function to call when the function finishes successfully.
1434          * This function will be called with a single parameter of type Date.
1435          * @param {function} [config.failure] The function to call if this function encounters an error.
1436          * This function will be called with the following parameters:
1437          * <ul>
1438          * <li><b>errorInfo:</b> An object with a property called "exception," which contains the error message.</li>
1439          * </ul>
1440          * @returns {Mixed} In client-side scripts, this method will return a transaction id
1441          * for the async request that can be used to cancel the request
1442          * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.data.Connection&member=abort" target="_blank">Ext.data.Connection.abort</a>).
1443          * In server-side scripts, this method will return the JSON response object (first parameter of the success or failure callbacks.)
1444          */
1445         getServerDate : function(config)
1446         {
1447             return LABKEY.Ajax.request({
1448                 url: LABKEY.ActionURL.buildURL('query', 'getServerDate.api'),
1449                 failure: LABKEY.Utils.getCallbackWrapper(LABKEY.Utils.getOnFailure(config), config.scope),
1450                 success: LABKEY.Utils.getCallbackWrapper(function(json){
1451                     var d;
1452                     var onSuccess = LABKEY.Utils.getOnSuccess(config);
1453                     if (json && json.date && onSuccess)
1454                     {
1455                         d = new Date(json.date);
1456                         onSuccess(d);
1457                     }
1458                 }, this)
1459             });
1460         },
1461 
1462 
1463         /**
1464          * Converts a javascript date into a format suitable for using in a LabKey SQL query, includes time but not milliseconds.
1465          * @param {Date} date JavaScript date
1466          * @param {Boolean} withMS include milliseconds
1467          * @returns {String} a date and time literal formatted to be used in a LabKey query
1468          */
1469         sqlDateTimeLiteral : function(date, withMS)
1470         {
1471             if (date === undefined || date === null || !date)
1472                 return "NULL";
1473             if (typeof date == "string")
1474             {
1475                 try { date = new Date(date); } catch (x) { }
1476             }
1477             if (typeof date == "object" && typeof date.toISOString == "function")
1478             {
1479                 var fmt2 = function(a) {return (a>=10 ?  ""+a : "0"+a);};
1480                 var fmt3 = function(a) {return (a>=100 ? ""+a : "0"+fmt2(a));};
1481                 return "{ts '" +
1482                         date.getFullYear() + "-" + fmt2(date.getMonth()+1) + "-" +fmt2(date.getDate()) + " " + fmt2(date.getHours()) + ":" + fmt2(date.getMinutes()) + ":" + fmt2(date.getSeconds()) +
1483                         (withMS ? "." + fmt3(date.getMilliseconds()) : "")
1484                         + "'}";
1485             }
1486             return "{ts '" + this.sqlStringLiteral(date) + "'}";
1487         },
1488 
1489 
1490         /**
1491          * Converts a JavaScript date into a format suitable for using in a LabKey SQL query, does not include time.
1492          * @param {Date} date JavaScript date
1493          * @returns {String} a date literal formatted to be used in a LabKey query
1494          */
1495         sqlDateLiteral : function(date)
1496         {
1497             if (date === undefined || date === null || !date)
1498                 return "NULL";
1499             if (typeof date == "string")
1500             {
1501                 try { date = new Date(date); } catch (x) { }
1502             }
1503             if (typeof date == "object" && typeof date.toISOString == "function")
1504             {
1505                 var fmt2 = function(a) {return (a>=10 ? a : "0"+a);};
1506                 var fmt3 = function(a) {return (a>=999 ? a : "0"+fmt2(a));};
1507                 return "{d '" +
1508                         date.getFullYear() + "-" + fmt2(date.getMonth()+1) + "-" +fmt2(date.getDate())
1509                         + "'}";
1510             }
1511             return "{d '" + this.sqlStringLiteral(date) + "'}";
1512         },
1513 
1514 
1515         /**
1516          * Converts a JavaScript string into a format suitable for using in a LabKey SQL query.
1517          * @param {string} str String to use in query
1518          * @returns {string} value formatted for use in a LabKey query.  Will properly escape single quote characters.
1519          */
1520         sqlStringLiteral : function(str)
1521         {
1522             if (str === undefined || str === null || str == '')
1523                 return "NULL";
1524             str = str.toString();
1525             return "'" + str.replace("'","''") + "'";
1526         },
1527 
1528         URL_COLUMN_PREFIX: "_labkeyurl_"
1529     };
1530 };
1531 
1532 /**
1533  * @class This class is used to construct filters when using APIs such as {@link LABKEY.Query.GetData.getRawData},
1534  *      {@link LABKEY.Query.selectRows}, or {@link LABKEY.Query.executeSql}. This is the base filter class, which requires
1535  *      the user specify a filter type from {@link LABKEY.Filter#Types}. Users can avoid the need for specifying a filter
1536  *      type by using a subclass of Filter such as {@link LABKEY.Query.Filter.Equals} or {@link LABKEY.Query.Filter.GreaterThan}, which
1537  *      will automatically set the type for the user.
1538  * @param {String} columnName Required. The name of the column the filter will be applied  Can be a string, array of strings,
1539  * or a {@link LABKEY.FieldKey}
1540  * @param value Value used as the filter criterion or an Array of values.
1541  * @param {LABKEY.Filter#Types} filterType Type of filter to apply to the 'column' using the 'value'
1542  * @constructor
1543  */
1544 LABKEY.Query.Filter = function (columnName, value, filterType)
1545 {
1546     if (columnName) {
1547         if (columnName instanceof LABKEY.FieldKey) {
1548             columnName = columnName.toString();
1549         }
1550         else if (columnName instanceof Array) {
1551             columnName = columnName.join('/');
1552         }
1553     }
1554 
1555     if (!filterType)
1556     {
1557         filterType = LABKEY.Filter.Types.EQUAL;
1558     }
1559 
1560     /**
1561      * @private
1562      */
1563     this.columnName = columnName;
1564 
1565     /**
1566      * @private
1567      */
1568     this.value = value;
1569 
1570     /**
1571      * @private
1572      */
1573     this.filterType = filterType;
1574 };
1575 
1576 /**
1577  * Gets the column name used in the filter.
1578  * @returns {String}
1579  */
1580 LABKEY.Query.Filter.prototype.getColumnName = function ()
1581 {
1582     return this.columnName
1583 };
1584 
1585 /**
1586  * Gets the filter type used to construct the filter.
1587  * @returns {LABKEY.Filter#Types}
1588  */
1589 LABKEY.Query.Filter.prototype.getFilterType = function ()
1590 {
1591     return this.filterType
1592 };
1593 
1594 /**
1595  * Returns the value of the filter.
1596  * @returns {*}
1597  */
1598 LABKEY.Query.Filter.prototype.getValue = function ()
1599 {
1600     return this.value
1601 };
1602 
1603 /**
1604  * Returns the value that will be put on URL.
1605  * @returns {String}
1606  */
1607 LABKEY.Query.Filter.prototype.getURLParameterValue = function ()
1608 {
1609     return this.filterType.isDataValueRequired() ? this.value : ''
1610 };
1611 
1612 /**
1613  * Returns the URL parameter name used for the filter.
1614  * @param dataRegionName The dataRegionName the filter is associated with.
1615  * @returns {String}
1616  */
1617 LABKEY.Query.Filter.prototype.getURLParameterName = function (dataRegionName)
1618 {
1619     return (dataRegionName || "query") + "." + this.columnName + "~" + this.filterType.getURLSuffix();
1620 };
1621 
1622 LABKEY.Query.Filter.HasAnyValue = function (columnName)
1623 {
1624     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.HAS_ANY_VALUE);
1625 };
1626 LABKEY.Query.Filter.HasAnyValue.prototype = new LABKEY.Query.Filter;
1627 
1628 /**
1629  * @class LABKEY.Query.Filter.Equal subclass of {@link LABKEY.Query.Filter}.
1630  *      Finds rows where the column value matches the given filter value. Case-sensitivity depends upon how your
1631  *      underlying relational database was configured.
1632  * @augments LABKEY.Query.Filter
1633  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1634  * or a {@link LABKEY.FieldKey}
1635  * @param value Value used as the filter criterion or an Array of values.
1636  * @constructor
1637  */
1638 LABKEY.Query.Filter.Equal = function (columnName, value)
1639 {
1640     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.EQUAL);
1641 };
1642 LABKEY.Query.Filter.Equal.prototype = new LABKEY.Query.Filter;
1643 
1644 /**
1645  * @class LABKEY.Query.Filter.DateEqual subclass of {@link LABKEY.Query.Filter}.
1646  *      Finds rows where the date portion of a datetime column matches the filter value (ignoring the time portion).
1647  * @augments LABKEY.Query.Filter
1648  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1649  * or a {@link LABKEY.FieldKey}
1650  * @param value Value used as the filter criterion or an Array of values.
1651  * @constructor
1652  */
1653 LABKEY.Query.Filter.DateEqual = function (columnName, value)
1654 {
1655     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DATE_EQUAL);
1656 };
1657 LABKEY.Query.Filter.DateEqual.prototype = new LABKEY.Query.Filter;
1658 
1659 /**
1660  * @class LABKEY.Query.Filter.DateNotEqual subclass of {@link LABKEY.Query.Filter}.
1661  *      Finds rows where the date portion of a datetime column does not match the filter value (ignoring the time portion).
1662  * @augments LABKEY.Query.Filter
1663  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1664  * or a {@link LABKEY.FieldKey}
1665  * @param value Value used as the filter criterion or an Array of values.
1666  * @constructor
1667  */
1668 LABKEY.Query.Filter.DateNotEqual = function (columnName, value)
1669 {
1670     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DATE_NOT_EQUAL);
1671 };
1672 LABKEY.Query.Filter.DateNotEqual.prototype = new LABKEY.Query.Filter;
1673 
1674 /**
1675  * @class LABKEY.Query.Filter.NotEqualOrNull subclass of {@link LABKEY.Query.Filter}.
1676  *      Finds rows where the column value does not equal the filter value, or is missing (null).
1677  * @augments LABKEY.Query.Filter
1678  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1679  * or a {@link LABKEY.FieldKey}
1680  * @param value Value used as the filter criterion or an Array of values.
1681  * @constructor
1682  */
1683 LABKEY.Query.Filter.NotEqualOrNull = function (columnName, value)
1684 {
1685     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.NEQ_OR_NULL);
1686 };
1687 LABKEY.Query.Filter.NotEqualOrNull.prototype = new LABKEY.Query.Filter;
1688 
1689 /**
1690  * @class LABKEY.Query.Filter.NotEqualOrMissing subclass of {@link LABKEY.Query.Filter}.
1691  *      Finds rows where the column value does not equal the filter value, or is missing (null).
1692  * @augments LABKEY.Query.Filter
1693  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1694  * or a {@link LABKEY.FieldKey}
1695  * @param value Value used as the filter criterion or an Array of values.
1696  * @constructor
1697  */
1698 LABKEY.Query.Filter.NotEqualOrMissing = function (columnName, value)
1699 {
1700     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.NOT_EQUAL_OR_MISSING);
1701 };
1702 LABKEY.Query.Filter.NotEqualOrMissing.prototype = new LABKEY.Query.Filter;
1703 
1704 /**
1705  * @class LABKEY.Query.Filter.NotEqual subclass of {@link LABKEY.Query.Filter}.
1706  *      Finds rows where the column value does not equal the filter value.
1707  * @augments LABKEY.Query.Filter
1708  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1709  * or a {@link LABKEY.FieldKey}
1710  * @param value Value used as the filter criterion or an Array of values.
1711  * @constructor
1712  */
1713 LABKEY.Query.Filter.NotEqual = function (columnName, value)
1714 {
1715     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.NOT_EQUAL);
1716 };
1717 LABKEY.Query.Filter.NotEqual.prototype = new LABKEY.Query.Filter;
1718 
1719 /**
1720  * @class LABKEY.Query.Filter.Neq subclass of {@link LABKEY.Query.Filter}.
1721  *      Finds rows where the column value does not equal the filter value.
1722  * @augments LABKEY.Query.Filter
1723  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1724  * or a {@link LABKEY.FieldKey}
1725  * @param value Value used as the filter criterion or an Array of values.
1726  * @constructor
1727  */
1728 LABKEY.Query.Filter.Neq = function (columnName, value)
1729 {
1730     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.NEQ);
1731 };
1732 LABKEY.Query.Filter.Neq.prototype = new LABKEY.Query.Filter;
1733 
1734 /**
1735  * @class LABKEY.Query.Filter.Neq subclass of {@link LABKEY.Query.Filter}.
1736  *      Finds rows where the column value is blank.
1737  * @augments LABKEY.Query.Filter
1738  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1739  * or a {@link LABKEY.FieldKey}
1740  * @constructor
1741  */
1742 LABKEY.Query.Filter.IsBlank = function (columnName)
1743 {
1744     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.ISBLANK);
1745 };
1746 LABKEY.Query.Filter.IsBlank.prototype = new LABKEY.Query.Filter;
1747 
1748 /**
1749  * @class LABKEY.Query.Filter.Missing subclass of {@link LABKEY.Query.Filter}.
1750  *      Finds rows where the column value is missing (null). Note that no filter value is required with this operator.
1751  * @augments LABKEY.Query.Filter
1752  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1753  * or a {@link LABKEY.FieldKey}
1754  * @constructor
1755  */
1756 LABKEY.Query.Filter.Missing = function (columnName)
1757 {
1758     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.MISSING);
1759 };
1760 LABKEY.Query.Filter.Missing.prototype = new LABKEY.Query.Filter;
1761 
1762 /**
1763  * @class LABKEY.Query.Filter.NonBlank subclass of {@link LABKEY.Query.Filter}.
1764  *      Finds rows where the column value is not blank.
1765  * @augments LABKEY.Query.Filter
1766  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1767  * or a {@link LABKEY.FieldKey}
1768  * @constructor
1769  */
1770 LABKEY.Query.Filter.NonBlank = function (columnName)
1771 {
1772     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.NONBLANK);
1773 };
1774 LABKEY.Query.Filter.NonBlank.prototype = new LABKEY.Query.Filter;
1775 
1776 /**
1777  * @class LABKEY.Query.Filter.NotMissing subclass of {@link LABKEY.Query.Filter}.
1778  *      Finds rows where the column value is not missing.
1779  * @augments LABKEY.Query.Filter
1780  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1781  * or a {@link LABKEY.FieldKey}
1782  * @constructor
1783  */
1784 LABKEY.Query.Filter.NotMissing = function (columnName)
1785 {
1786     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.NOT_MISSING);
1787 };
1788 LABKEY.Query.Filter.NotMissing.prototype = new LABKEY.Query.Filter;
1789 
1790 /**
1791  * @class LABKEY.Query.Filter.Gt subclass of {@link LABKEY.Query.Filter}.
1792  *      Finds rows where the column value is greater than the filter value.
1793  * @augments LABKEY.Query.Filter
1794  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1795  * or a {@link LABKEY.FieldKey}
1796  * @param value Value used as the filter criterion or an Array of values.
1797  * @constructor
1798  */
1799 LABKEY.Query.Filter.Gt = function (columnName, value)
1800 {
1801     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.GT);
1802 };
1803 LABKEY.Query.Filter.Gt.prototype = new LABKEY.Query.Filter;
1804 
1805 /**
1806  * @class LABKEY.Query.Filter.GreaterThan subclass of {@link LABKEY.Query.Filter}.
1807  *      Finds rows where the column value is greater than the filter value.
1808  * @augments LABKEY.Query.Filter
1809  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1810  * or a {@link LABKEY.FieldKey}
1811  * @param value Value used as the filter criterion or an Array of values.
1812  * @constructor
1813  */
1814 LABKEY.Query.Filter.GreaterThan = function (columnName, value)
1815 {
1816     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.GREATER_THAN);
1817 };
1818 LABKEY.Query.Filter.GreaterThan.prototype = new LABKEY.Query.Filter;
1819 
1820 /**
1821  * @class LABKEY.Query.Filter.Lt subclass of {@link LABKEY.Query.Filter}.
1822  *      Finds rows where the column value is less than the filter value.
1823  * @augments LABKEY.Query.Filter
1824  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1825  * or a {@link LABKEY.FieldKey}
1826  * @param value Value used as the filter criterion or an Array of values.
1827  * @constructor
1828  */
1829 LABKEY.Query.Filter.Lt = function (columnName, value)
1830 {
1831     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.LT);
1832 };
1833 LABKEY.Query.Filter.Lt.prototype = new LABKEY.Query.Filter;
1834 
1835 /**
1836  * @class LABKEY.Query.Filter.LessThan subclass of {@link LABKEY.Query.Filter}.
1837  *      Finds rows where the column value is less than the filter value.
1838  * @augments LABKEY.Query.Filter
1839  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1840  * or a {@link LABKEY.FieldKey}
1841  * @param value Value used as the filter criterion or an Array of values.
1842  * @constructor
1843  */
1844 LABKEY.Query.Filter.LessThan = function (columnName, value)
1845 {
1846     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.LESS_THAN);
1847 };
1848 LABKEY.Query.Filter.LessThan.prototype = new LABKEY.Query.Filter;
1849 
1850 /**
1851  * @class LABKEY.Query.Filter.DateLessThan subclass of {@link LABKEY.Query.Filter}.
1852  *      Finds rows where the date portion of a datetime column is less than the filter value (ignoring the time portion).
1853  * @augments LABKEY.Query.Filter
1854  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1855  * or a {@link LABKEY.FieldKey}
1856  * @param value Value used as the filter criterion or an Array of values.
1857  * @constructor
1858  */
1859 LABKEY.Query.Filter.DateLessThan = function (columnName, value)
1860 {
1861     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DATE_LESS_THAN);
1862 };
1863 LABKEY.Query.Filter.DateLessThan.prototype = new LABKEY.Query.Filter;
1864 
1865 /**
1866  * @class LABKEY.Query.Filter.Gte subclass of {@link LABKEY.Query.Filter}.
1867  *      Finds rows where the column value is greater than or equal to the filter value.
1868  * @augments LABKEY.Query.Filter
1869  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1870  * or a {@link LABKEY.FieldKey}
1871  * @param value Value used as the filter criterion or an Array of values.
1872  * @constructor
1873  */
1874 LABKEY.Query.Filter.Gte = function (columnName, value)
1875 {
1876     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.GTE);
1877 };
1878 LABKEY.Query.Filter.Gte.prototype = new LABKEY.Query.Filter;
1879 
1880 /**
1881  * @class LABKEY.Query.Filter.GreaterThanOrEqual subclass of {@link LABKEY.Query.Filter}.
1882  *      Finds rows where the column value is greater than or equal to the filter value.
1883  * @augments LABKEY.Query.Filter
1884  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1885  * or a {@link LABKEY.FieldKey}
1886  * @param value Value used as the filter criterion or an Array of values.
1887  * @constructor
1888  */
1889 LABKEY.Query.Filter.GreaterThanOrEqual = function (columnName, value)
1890 {
1891     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.GREATER_THAN_OR_EQUAL);
1892 };
1893 LABKEY.Query.Filter.GreaterThanOrEqual.prototype = new LABKEY.Query.Filter;
1894 
1895 /**
1896  * @class LABKEY.Query.Filter.GreaterThanOrEqual subclass of {@link LABKEY.Query.Filter}.
1897  *      Finds rows where the date portion of a datetime column is greater than or equal to the filter value
1898  *      (ignoring the time portion).
1899  * @augments LABKEY.Query.Filter
1900  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1901  * or a {@link LABKEY.FieldKey}
1902  * @param value Value used as the filter criterion or an Array of values.
1903  * @constructor
1904  */
1905 LABKEY.Query.Filter.DateGreaterThanOrEqual = function (columnName, value)
1906 {
1907     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DATE_GREATER_THAN_OR_EQUAL);
1908 };
1909 LABKEY.Query.Filter.DateGreaterThanOrEqual.prototype = new LABKEY.Query.Filter;
1910 
1911 /**
1912  * @class LABKEY.Query.Filter.Lte subclass of {@link LABKEY.Query.Filter}.
1913  *      Finds rows where the column value is less than or equal to the filter value.
1914  * @augments LABKEY.Query.Filter
1915  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1916  * or a {@link LABKEY.FieldKey}
1917  * @param value Value used as the filter criterion or an Array of values.
1918  * @constructor
1919  */
1920 LABKEY.Query.Filter.Lte = function (columnName, value)
1921 {
1922     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.LTE);
1923 };
1924 LABKEY.Query.Filter.Lte.prototype = new LABKEY.Query.Filter;
1925 
1926 /**
1927  * @class LABKEY.Query.Filter.LessThanOrEqual subclass of {@link LABKEY.Query.Filter}.
1928  *      Finds rows where the column value is less than or equal to the filter value.
1929  * @augments LABKEY.Query.Filter
1930  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1931  * or a {@link LABKEY.FieldKey}
1932  * @param value Value used as the filter criterion or an Array of values.
1933  * @constructor
1934  */
1935 LABKEY.Query.Filter.LessThanOrEqual = function (columnName, value)
1936 {
1937     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.LESS_THAN_OR_EQUAL);
1938 };
1939 LABKEY.Query.Filter.LessThanOrEqual.prototype = new LABKEY.Query.Filter;
1940 
1941 /**
1942  * @class LABKEY.Query.Filter.DateLessThanOrEqual subclass of {@link LABKEY.Query.Filter}.
1943  *      Finds rows where the date portion of a datetime column is less than or equal to the filter value
1944  *      (ignoring the time portion).
1945  * @augments LABKEY.Query.Filter
1946  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1947  * or a {@link LABKEY.FieldKey}
1948  * @param value Value used as the filter criterion or an Array of values.
1949  * @constructor
1950  */
1951 LABKEY.Query.Filter.DateLessThanOrEqual = function (columnName, value)
1952 {
1953     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DATE_LESS_THAN_OR_EQUAL);
1954 };
1955 LABKEY.Query.Filter.DateLessThanOrEqual.prototype = new LABKEY.Query.Filter;
1956 
1957 /**
1958  * @class LABKEY.Query.Filter.Contains subclass of {@link LABKEY.Query.Filter}.
1959  *      Finds rows where the column value contains the filter value. Note that this may result in a slow query as this
1960  *      cannot use indexes.
1961  * @augments LABKEY.Query.Filter
1962  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1963  * or a {@link LABKEY.FieldKey}
1964  * @param value Value used as the filter criterion or an Array of values.
1965  * @constructor
1966  */
1967 LABKEY.Query.Filter.Contains = function (columnName, value)
1968 {
1969     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.CONTAINS);
1970 };
1971 LABKEY.Query.Filter.Contains.prototype = new LABKEY.Query.Filter;
1972 
1973 /**
1974  * @class LABKEY.Query.Filter.DoesNotContain subclass of {@link LABKEY.Query.Filter}.
1975  *      Finds rows where the column value does not contain the filter value. Note that this may result in a slow query
1976  *      as this cannot use indexes.
1977  * @augments LABKEY.Query.Filter
1978  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1979  * or a {@link LABKEY.FieldKey}
1980  * @param value Value used as the filter criterion or an Array of values.
1981  * @constructor
1982  */
1983 LABKEY.Query.Filter.DoesNotContain = function (columnName, value)
1984 {
1985     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.DOES_NOT_CONTAIN);
1986 };
1987 LABKEY.Query.Filter.DoesNotContain.prototype = new LABKEY.Query.Filter;
1988 
1989 /**
1990  * @class LABKEY.Query.Filter.StartsWith subclass of {@link LABKEY.Query.Filter}.
1991  *      Finds rows where the column value starts with the filter value.
1992  * @augments LABKEY.Query.Filter
1993  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
1994  * or a {@link LABKEY.FieldKey}
1995  * @param value Value used as the filter criterion or an Array of values.
1996  * @constructor
1997  */
1998 LABKEY.Query.Filter.StartsWith = function (columnName, value)
1999 {
2000     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.STARTS_WITH);
2001 };
2002 LABKEY.Query.Filter.StartsWith.prototype = new LABKEY.Query.Filter;
2003 
2004 /**
2005  * @class LABKEY.Query.Filter.In subclass of {@link LABKEY.Query.Filter}.
2006  *      Finds rows where the column value equals one of the supplied filter values. The values should be supplied as a
2007  *      semi-colon-delimited list (example usage: a;b;c).
2008  * @augments LABKEY.Query.Filter
2009  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2010  * or a {@link LABKEY.FieldKey}
2011  * @param value Value used as the filter criterion or an Array of values.
2012  * @constructor
2013  */
2014 LABKEY.Query.Filter.In = function (columnName, value)
2015 {
2016     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.IN);
2017 };
2018 LABKEY.Query.Filter.In.prototype = new LABKEY.Query.Filter;
2019 
2020 /**
2021  * @class LABKEY.Query.Filter.EqualsOneOf subclass of {@link LABKEY.Query.Filter}.
2022  *      Finds rows where the column value equals one of the supplied filter values. The values should be supplied as a
2023  *      semi-colon-delimited list (example usage: a;b;c).
2024  * @augments LABKEY.Query.Filter
2025  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2026  * or a {@link LABKEY.FieldKey}
2027  * @param value Value used as the filter criterion or an Array of values.
2028  * @constructor
2029  */
2030 LABKEY.Query.Filter.EqualsOneOf = function (columnName, value)
2031 {
2032     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.EQUALS_ONE_OF);
2033 };
2034 LABKEY.Query.Filter.EqualsOneOf.prototype = new LABKEY.Query.Filter;
2035 
2036 /**
2037  * @class LABKEY.Query.Filter.EqualsNoneOf subclass of {@link LABKEY.Query.Filter}.
2038  *      Finds rows where the column value does not equal one of the supplied filter values. The values should be supplied as a
2039  *      semi-colon-delimited list (example usage: a;b;c).
2040  * @augments LABKEY.Query.Filter
2041  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2042  * or a {@link LABKEY.FieldKey}
2043  * @param value Value used as the filter criterion or an Array of values.
2044  * @constructor
2045  */
2046 LABKEY.Query.Filter.EqualsNoneOf = function (columnName, value)
2047 {
2048     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.EQUALS_NONE_OF);
2049 };
2050 LABKEY.Query.Filter.EqualsNoneOf.prototype = new LABKEY.Query.Filter;
2051 
2052 /**
2053  * @class LABKEY.Query.Filter.NotIn subclass of {@link LABKEY.Query.Filter}.
2054  *      Finds rows where the column value is not in any of the supplied filter values. The values should be supplied as
2055  *      a semi-colon-delimited list (example usage: a;b;c).
2056  * @augments LABKEY.Query.Filter
2057  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2058  * or a {@link LABKEY.FieldKey}
2059  * @param value Value used as the filter criterion or an Array of values.
2060  * @constructor
2061  */
2062 LABKEY.Query.Filter.NotIn = function (columnName, value)
2063 {
2064     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.NOT_IN);
2065 };
2066 LABKEY.Query.Filter.NotIn.prototype = new LABKEY.Query.Filter;
2067 
2068 /**
2069  * @class LABKEY.Query.Filter.ContainsOneOf subclass of {@link LABKEY.Query.Filter}.
2070  *      Finds rows where the column value contains any of the supplied filter values. The values should be supplied as a
2071  *      semi-colon-delimited list (example usage: a;b;c).
2072  * @augments LABKEY.Query.Filter
2073  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2074  * or a {@link LABKEY.FieldKey}
2075  * @param value Value used as the filter criterion or an Array of values.
2076  * @constructor
2077  */
2078 LABKEY.Query.Filter.ContainsOneOf = function (columnName, value)
2079 {
2080     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.CONTAINS_ONE_OF);
2081 };
2082 LABKEY.Query.Filter.ContainsOneOf.prototype = new LABKEY.Query.Filter;
2083 
2084 /**
2085  * @class LABKEY.Query.Filter.MemberOf subclass of {@link LABKEY.Query.Filter}.
2086  *      Finds rows where the column value corresponds to a user that is a member of a group with the id of the supplied filter value.
2087  * @augments LABKEY.Query.Filter
2088  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2089  * or a {@link LABKEY.FieldKey}
2090  * @param value Value used as the filter criterion.
2091  * @constructor
2092  */
2093 LABKEY.Query.Filter.MemberOf = function (columnName, value)
2094 {
2095     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.MEMBER_OF);
2096 };
2097 LABKEY.Query.Filter.ContainsOneOf.prototype = new LABKEY.Query.Filter;
2098 
2099 /**
2100  * @class LABKEY.Query.Filter.ContainsNoneOf subclass of {@link LABKEY.Query.Filter}.
2101  *      Finds rows where the column value does not contain any of the supplied filter values. The values should be supplied
2102  *      as a semi-colon-delimited list (example usage: a;b;c).
2103  * @augments LABKEY.Query.Filter
2104  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2105  * or a {@link LABKEY.FieldKey}
2106  * @param value Value used as the filter criterion or an Array of values.
2107  * @constructor
2108  */
2109 LABKEY.Query.Filter.ContainsNoneOf = function (columnName, value)
2110 {
2111     LABKEY.Query.Filter.call(this, columnName, value, LABKEY.Filter.Types.CONTAINS_NONE_OF);
2112 };
2113 LABKEY.Query.Filter.ContainsNoneOf.prototype = new LABKEY.Query.Filter;
2114 
2115 /**
2116  * @class LABKEY.Query.Filter.HasMissingValue subclass of {@link LABKEY.Query.Filter}.
2117  *      Finds rows that have a missing value indicator.
2118  * @augments LABKEY.Query.Filter
2119  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2120  * or a {@link LABKEY.FieldKey}
2121  * @constructor
2122  */
2123 LABKEY.Query.Filter.HasMissingValue = function (columnName)
2124 {
2125     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.HAS_MISSING_VALUE);
2126 };
2127 LABKEY.Query.Filter.HasMissingValue.prototype = new LABKEY.Query.Filter;
2128 
2129 /**
2130  * @class LABKEY.Query.Filter.DoesNotHaveMissingValue subclass of {@link LABKEY.Query.Filter}.
2131  *      Finds rows that do not have a missing value indicator.
2132  * @augments LABKEY.Query.Filter
2133  * @param columnName Required. The name of the column the filter will be applied to. Can be a string, array of strings,
2134  * or a {@link LABKEY.FieldKey}
2135  * @constructor
2136  */
2137 LABKEY.Query.Filter.DoesNotHaveMissingValue = function (columnName)
2138 {
2139     LABKEY.Query.Filter.call(this, columnName, null, LABKEY.Filter.Types.DOES_NOT_HAVE_MISSING_VALUE);
2140 };
2141 LABKEY.Query.Filter.DoesNotHaveMissingValue.prototype = new LABKEY.Query.Filter;
2142 
2143 (function(){
2144     /**
2145      * @class LABKEY.Query.Row The class used to wrap each row object returned from the server during a GetData, executeSql,
2146      * or selectRows request. Most users will not instantiate these themselves. Instead they will interact with them during
2147      * the success handler of the API they are using.
2148      * @see LABKEY.Query.Response
2149      * @param row The raw row from a GetData or executeSQL, selectRows (version 13.2 and above) request.
2150      * @constructor
2151      */
2152     LABKEY.Query.Row = function(row){
2153         this.links = null;
2154 
2155         if(row.links){
2156             this.links = row.links;
2157         }
2158 
2159         for (var attr in row.data) {
2160             if (row.data.hasOwnProperty(attr)) {
2161                 this[attr] = row.data[attr];
2162             }
2163         }
2164     };
2165 
2166     /**
2167      * Gets the requested column from the row. Includes extended values such as display value, URL, etc.
2168      * When requested version is >16.2, multi-value columns will return an array of objects containing "value" and other properties.
2169      * @param {String} columnName The column name requested. Used to do a case-insensitive match to find the column.
2170      * @returns {Object} For the given columnName, returns an object in the common case or an array of objects for multi-value columns.
2171      * The object will always contain a property named "value" that is the column's value, but it may also contain other properties about that column's value. For
2172      * example, if the column was setup to track missing value information, it will also contain a property named mvValue
2173      * (which is the raw value that is considered suspect), and a property named mvIndicator, which will be the string MV
2174      * indicator (e.g., "Q").
2175      */
2176     LABKEY.Query.Row.prototype.get = function(columnName){
2177         columnName = columnName.toLowerCase();
2178 
2179         for (var attr in this) {
2180             if (attr.toLowerCase() === columnName && this.hasOwnProperty(attr) && !(this[attr] instanceof Function)) {
2181                 return this[attr];
2182             }
2183         }
2184 
2185         return null;
2186     };
2187 
2188     /**
2189      * Gets the simple value for the requested column. Equivalent of doing Row.get(columnName).value.
2190      * For multi-value columns, the result is an array of values.
2191      * @param {String} columnName The column name requested. Used to do a case-insensitive match to find the column.
2192      * @returns {*} Returns the simple value for the given column.
2193      */
2194     LABKEY.Query.Row.prototype.getValue = function(columnName){
2195         columnName = columnName.toLowerCase();
2196 
2197         for (var attr in this) {
2198             if (attr.toLowerCase() === columnName && this.hasOwnProperty(attr) && !(this[attr] instanceof Function)) {
2199                 if (LABKEY.Utils.isArray(this[attr])) {
2200                     return this[attr].map(function (i) { return i.value; });
2201                 }
2202                 if (this[attr].hasOwnProperty('value')) {
2203                     return this[attr].value;
2204                 }
2205             }
2206         }
2207 
2208         return null;
2209     };
2210 
2211     /**
2212      * Gets all of the links for a row (details, update, etc.).
2213      * @returns {Object} Returns an object with all of the links types (details, update, etc.) for a row.
2214      */
2215     LABKEY.Query.Row.prototype.getLinks = function(){
2216         return this.links;
2217     };
2218 
2219     /**
2220      * Gets a specific link type for a row (details, update, etc.).
2221      * @param linkType Required. The name of the link type to be returned.
2222      * @returns {Object} Returns an object with the display text and link value.
2223      */
2224     LABKEY.Query.Row.prototype.getLink = function(linkType){
2225         if (this.links[linkType]) {
2226             return this.links[linkType];
2227         }
2228 
2229         return null;
2230     };
2231 
2232     /**
2233      * @private
2234      */
2235     var generateColumnModel = function(fields) {
2236         var i, columns = [];
2237 
2238         for (i = 0; i < fields.length; i++) {
2239             columns.push({
2240                 scale: fields[i].scale,
2241                 hidden: fields[i].hidden,
2242                 sortable: fields[i].sortable,
2243                 align: fields[i].align,
2244                 width: fields[i].width,
2245                 dataIndex: fields[i].fieldKey.toString(),
2246                 required: fields[i].nullable, // Not sure if this is correct.
2247                 editable: fields[i].userEditable,
2248                 header: fields[i].shortCaption
2249             })
2250         }
2251 
2252         return columns;
2253     };
2254 
2255     /**
2256      * @private
2257      */
2258     var generateGetDisplayField = function(fieldKeyToFind, fields) {
2259         return function() {
2260             var fieldString = fieldKeyToFind.toString();
2261             for (var i = 0; i < fields.length; i++) {
2262                 if (fieldString == fields[i].fieldKey.toString()) {
2263                     return fields[i];
2264                 }
2265             }
2266             return null;
2267         };
2268     };
2269 
2270     /**
2271      * @class The class used to wrap the response object from {@link LABKEY.Query.GetData.getRawData},
2272      *      {@link LABKEY.Query.selectRows}, and {@link LABKEY.Query.executeSql}.
2273      * @param response The raw JSON response object returned from the server when executing {@link LABKEY.Query.GetData.getRawData},
2274      *      {@link LABKEY.Query.selectRows}, or {@link LABKEY.Query.executeSql} when requiredVersion is 13.2.
2275      * @see LABKEY.Query.GetData.getRawData
2276      * @see LABKEY.Query.selectRows
2277      * @see LABKEY.Query.executeSql
2278      * @constructor
2279      */
2280     LABKEY.Query.Response = function(response) {
2281         // response = response;
2282         var i, attr;
2283 
2284         // Shallow copy the response.
2285         for (attr in response) {
2286             if (response.hasOwnProperty(attr)) {
2287                 this[attr] = response[attr];
2288             }
2289         }
2290 
2291         // Wrap the Schema, Lookup, and Field Keys.
2292         this.schemaKey = LABKEY.SchemaKey.fromParts(response.schemaName);
2293 
2294         for (i = 0; i < response.metaData.fields.length; i++) {
2295             var field = response.metaData.fields[i],
2296                 lookup = field.lookup;
2297 
2298             field.fieldKey = LABKEY.FieldKey.fromParts(field.fieldKey);
2299 
2300             if (lookup && lookup.schemaName) {
2301                 lookup.schemaName = LABKEY.SchemaKey.fromParts(lookup.schemaName);
2302             }
2303 
2304             if (field.displayField) {
2305                 field.displayField = LABKEY.FieldKey.fromParts(field.displayField);
2306                 field.getDisplayField = generateGetDisplayField(field.displayField, response.metaData.fields);
2307             }
2308 
2309             // Only parse the 'extFormatFn' if ExtJS is present
2310             if (field.extFormatFn && window && (window.Ext !== undefined || window.Ext4 !== undefined)) {
2311                 field.extFormatFn = eval(field.extFormatFn);
2312             }
2313         }
2314 
2315         // Generate Column Model
2316         this.columnModel = generateColumnModel(this.metaData.fields);
2317 
2318         // Wrap the rows -- may not be in the response (e.g. maxRows: 0)
2319         if (this.rows !== undefined) {
2320             for (i = 0; i < this.rows.length; i++) {
2321                 this.rows[i] = new LABKEY.Query.Row(this.rows[i]);
2322             }
2323         }
2324         else {
2325             this.rows = [];
2326         }
2327 
2328         return this;
2329     };
2330 
2331     /**
2332      * Gets the metaData object from the response.
2333      * @returns {Object} Returns an object with the following properties:
2334      * <ul>
2335      *     <li><strong>fields</strong>: {Object[]}
2336      *     Each field has the following properties:
2337      *          <ul>
2338      *              <li><strong>name</strong>: {String} The name of the field</li>
2339      *              <li><strong>type</strong>: {String} JavaScript type name of the field</li>
2340      *              <li><strong>shownInInsertView</strong>: {Boolean} whether this field is intended to be shown in insert views</li>
2341      *              <li><strong>shownInUpdateView</strong>: {Boolean} whether this field is intended to be shown in update views</li>
2342      *              <li><strong>shownInDetailsView</strong>: {Boolean} whether this field is intended to be shown in details views</li>
2343      *              <li>
2344      *                  <strong>measure</strong>: {Boolean} whether this field is a measure.  Measures are fields that contain data
2345      *                  subject to charting and other analysis.
2346      *              </li>
2347      *              <li>
2348      *                  <strong>dimension</strong>: {Boolean} whether this field is a dimension.  Data dimensions define logical groupings
2349      *                  of measures.
2350      *              </li>
2351      *              <li><strong>hidden</strong>: {Boolean} whether this field is hidden and not normally shown in grid views</li>
2352      *              <li><strong>lookup</strong>: {Object} If the field is a lookup, there will
2353      *                  be four sub-properties listed under this property:
2354      *                  schema, table, displayColumn, and keyColumn, which describe the schema, table, and
2355      *                  display column, and key column of the lookup table (query).
2356      *              </li>
2357      *              <li>
2358      *                  <strong>displayField</strong>: {{@link LABKEY.FieldKey}} If the field has a display field this is
2359      *                  the field key for that field.
2360      *              </li>
2361      *              <li>
2362      *                  <strong>getDisplayField</strong>: {Function} If the field has a display field this function will
2363      *                  return the metadata field object for that field.
2364      *              </li>
2365      *          </ul>
2366      *     </li>
2367      *
2368      *     <li><strong>id</strong>: Name of the primary key column.</li>
2369      *     <li>
2370      *         <strong>root</strong>: Name of the property containing rows ("rows"). This is mainly for the Ext
2371      *         grid component.
2372      *     </li>
2373      *     <li><strong>title</strong>:</li>
2374      *     <li>
2375      *         <strong>totalProperty</strong>: Name of the top-level property containing the row count ("rowCount") in our case.
2376      *         This is mainly for the Ext grid component.
2377      *     </li>
2378      * </ul>
2379      */
2380     LABKEY.Query.Response.prototype.getMetaData = function() {
2381         return this.metaData;
2382     };
2383 
2384     /**
2385      * Returns the schema name from the Response.
2386      * @param {Boolean} asString
2387      * @returns {*} If asString is true it returns a string, otherwise it returns a {@link LABKEY.FieldKey} object.
2388      */
2389     LABKEY.Query.Response.prototype.getSchemaName = function(asString) {
2390         return asString ? this.schemaKey.toString() : this.schemaName;
2391     };
2392 
2393     /**
2394      * Returns the query name from the Response.
2395      * @returns {String}
2396      */
2397     LABKEY.Query.Response.prototype.getQueryName = function() {
2398         return this.queryName;
2399     };
2400 
2401     /**
2402      * Returns an array of objects that can be used to assist in creating grids using ExtJs.
2403      * @returns {Array} Returns an array of Objects that can be used to assist in creating Ext Grids to
2404      *      render the data.
2405      */
2406     LABKEY.Query.Response.prototype.getColumnModel = function() {
2407         return this.columnModel;
2408     };
2409 
2410     /**
2411      * Returns the array of row objects.
2412      * @returns {Array} Returns an array of {@link LABKEY.Query.Row} objects.
2413      */
2414     LABKEY.Query.Response.prototype.getRows = function() {
2415         return this.rows;
2416     };
2417 
2418     /**
2419      * Get a specific row from the row array.
2420      * @param {Integer} idx The index of the row you need.
2421      * @returns {LABKEY.Query.Row}
2422      */
2423     LABKEY.Query.Response.prototype.getRow = function(idx) {
2424         if (this.rows[idx] !== undefined) {
2425             return this.rows[idx];
2426         }
2427 
2428         throw new Error('No row found for index ' + idx);
2429     };
2430 
2431     /**
2432      * Gets the row count from the response, which is the total number of rows in the query, not necessarily the number
2433      * of rows returned. For example, if setting maxRows to 100 on a query that has 5,000 rows, getRowCount will return
2434      * 5,000, not 100.
2435      * @returns {Integer}
2436      */
2437     LABKEY.Query.Response.prototype.getRowCount = function() {
2438         return this.rowCount;
2439     };
2440 })();
2441 
2442 /**
2443 * @name LABKEY.Query.ModifyRowsOptions
2444 * @class   ModifyRowsOptions class to describe
2445             the third object passed to the successCallback function
2446             by {@link LABKEY.Query.updateRows}, {@link LABKEY.Query.insertRows} or
2447             {@link LABKEY.Query.deleteRows}. This object's properties are useful for
2448             matching requests to responses, as HTTP requests are typically
2449             processed asynchronously.
2450  *            <p>Additional Documentation:
2451  *              <ul>
2452  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2453  *                      How To Find schemaName, queryName & viewName</a></li>
2454  *              </ul>
2455  *           </p>
2456   * @see LABKEY.Query.updateRows
2457   * @see LABKEY.Query.insertRows
2458   * @see LABKEY.Query.deleteRows
2459 */
2460 
2461 /**#@+
2462 * @memberOf LABKEY.Query.ModifyRowsOptions#
2463 * @field
2464 */
2465 
2466 /**
2467 * @name headers
2468 * @description  An object containing one property for each HTTP header sent to the server.
2469 * @type Object
2470 */
2471 
2472 /**
2473 * @name method
2474 * @description The HTTP method used for the request (typically 'GET' or 'POST').
2475 * @type String
2476  */
2477 
2478 /**
2479 * @name url
2480 * @description  The URL that was requested.
2481 * @type String
2482 */
2483 
2484 /**
2485 * @name jsonData
2486 * @description  The data object sent to the server. This will contain the following properties:
2487           <ul>
2488             <li><b>schemaName</b>: String. The schema name being modified.  This is the same schemaName
2489                 the client passed to the calling function. </li>
2490             <li><b>queryName</b>: String. The query name being modified. This is the same queryName
2491                 the client passed to the calling function.  </li>
2492             <li><b>rows</b>: Object[]. Array of row objects that map the names of the row fields to their values.
2493             The fields required for inclusion for each row depend on the which LABKEY.Query method you are
2494             using (updateRows, insertRows or deleteRows). </li>
2495          </ul>
2496  <p/>
2497  <b>For {@link LABKEY.Query.updateRows}:</b> <p/>
2498  For the 'updateRows' method, each row in the rows array must include its primary key value
2499  as one of its fields.
2500  <p/>
2501  An example of a ModifyRowsOptions object for the 'updateRows' successCallback:
2502  <pre name="code" class="xml">
2503  {"schemaName": "lists",
2504   "queryName": "API Test List",
2505   "rows": [
2506  {"Key": 1,
2507  "FirstName": "Z",
2508  "Age": "100"}]
2509  } </pre></code>
2510 
2511  <p/>
2512  <b>For {@link LABKEY.Query.insertRows}:</b> <p/>
2513  For the 'insertRows' method, the fields of the rows should look the same as
2514  they do for the 'updateRows' method, except that primary key values for new rows
2515  need not be supplied if the primary key columns are auto-increment.
2516  <p/>
2517  An example of a ModifyRowsOptions object for the 'insertRows' successCallback:
2518  <pre name="code" class="xml">
2519  {"schemaName": "lists",
2520   "queryName": "API Test List",
2521   "rows": [
2522   {"FirstName": "C",
2523  "Age": "30"}]
2524  } </pre></code>
2525 
2526  <p/>
2527  <b>For {@link LABKEY.Query.deleteRows}:</b> <p/>
2528  For the 'deleteRows' method, the fields of the rows should look the
2529  same as they do for the 'updateRows' method, except that the 'deleteRows'
2530  method needs to supply only the primary key values for the rows. All
2531  other row data will be ignored.
2532  <p/>
2533  An example of a ModifyRowsOptions object for the 'deleteRows' successCallback:
2534  <pre name="code" class="xml">
2535  {"schemaName": "lists",
2536   "queryName": "API Test List",
2537   "rows": [
2538 {"Key": 3}]
2539  } </pre></code>
2540 * @type  Object
2541 */
2542 
2543 /**#@-*/
2544 
2545  /**
2546 * @name LABKEY.Query.ModifyRowsResults
2547 * @class  ModifyRowsResults class to describe
2548             the first object passed to the successCallback function
2549             by {@link LABKEY.Query.updateRows}, {@link LABKEY.Query.insertRows} or
2550             {@link LABKEY.Query.deleteRows}. This object's properties are useful for
2551             matching requests to responses, as HTTP requests are typically
2552             processed asynchronously.
2553   *            <p>Additional Documentation:
2554   *              <ul>
2555   *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2556   *                      How To Find schemaName, queryName & viewName</a></li>
2557   *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
2558   *                      <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a></li>
2559   *              </ul>
2560   *           </p>
2561 * @example For example:
2562         <pre name="code" class="xml">
2563         {  "schemaName": "lists",
2564            "queryName": "API Test List"
2565            "rowsAffected": 1,
2566            "command": "insert",
2567            "errors": [],
2568            "rows": [{ Key: 3, StringField: 'NewValue'}]
2569         } </pre></code>
2570 * @see LABKEY.Query.updateRows
2571 * @see LABKEY.Query.insertRows
2572 * @see LABKEY.Query.deleteRows
2573 * @see LABKEY.Query.saveRows
2574 */
2575 
2576 /**#@+
2577 * @memberOf LABKEY.Query.ModifyRowsResults#
2578 * @field
2579 */
2580 
2581 /**
2582 * @name LABKEY.Query.ModifyRowsResults#schemaName
2583 * @description  Contains the same schemaName the client passed to the calling function.
2584 * @type  String
2585 */
2586 
2587 /**
2588 * @name     LABKEY.Query.ModifyRowsResults#queryName
2589 * @description  Contains the same queryName the client passed to the calling function.
2590 * @type     String
2591 */
2592 
2593 /**
2594 * @name    command
2595 * @description   Will be "update", "insert", or "delete" depending on the API called.
2596 * @type    String
2597 */
2598 
2599 /**
2600 * @name    errors
2601 * @description   Objects will contain the properties 'id' (the field to which the error is related, if any),
2602 *                and 'msg' (the error message itself).
2603 * @type    Array
2604 */
2605 
2606 /**
2607 * @name  rowsAffected
2608 * @description  Indicates the number of rows affected by the API action.
2609             This will typically be the same number of rows passed in to the calling function.
2610 * @type        Integer
2611 */
2612 
2613 /**
2614 * @name LABKEY.Query.ModifyRowsResults#rows
2615 * @description   Array of rows with field values for the rows updated, inserted,
2616             or deleted, in the same order as the rows supplied in the request. For insert, the
2617             new key value for an auto-increment key will be in the returned row's field values.
2618             For insert or update, the other field values may also be different than those supplied
2619             as a result of database default expressions, triggers, or LabKey's automatic tracking
2620             feature, which automatically adjusts columns of certain names (e.g., Created, CreatedBy,
2621             Modified, ModifiedBy, etc.).
2622 * @type    Object[]
2623 */
2624 
2625 /**#@-*/
2626 
2627 /**
2628 * @name LABKEY.Query.SelectRowsOptions
2629 * @class  SelectRowsOptions class to describe
2630            the third object passed to the successCallback function by
2631            {@link LABKEY.Query.selectRows}.  This object's properties are useful for
2632            matching requests to responses, as HTTP requests are typically
2633            processed asynchronously.
2634  *            <p>Additional Documentation:
2635  *              <ul>
2636  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2637  *                      How To Find schemaName, queryName & viewName</a></li>
2638  *              </ul>
2639  *           </p>
2640 * @see LABKEY.Query.selectRows
2641 */
2642 
2643 /**#@+
2644 * @memberOf LABKEY.Query.SelectRowsOptions#
2645 * @field
2646 */
2647 
2648 /**
2649 * @name   query.schemaName
2650 * @description   Contains the same schemaName the client passed to the
2651             calling function. See <a class="link"
2652             href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2653             How To Find schemaName, queryName & viewName</a>.
2654 * @type   String
2655 */
2656 
2657 /**
2658 * @name   query.queryName
2659 * @description   Contains the same queryName the client passed
2660             to the calling function. See
2661             <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2662             How To Find schemaName, queryName & viewName</a>.
2663 * @type   String
2664 */
2665 
2666 /**
2667 * @name    query.viewName
2668 * @description 	Name of a valid custom view for the chosen queryName. See
2669             <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2670             How To Find schemaName, queryName & viewName</a>.
2671 * @type    String
2672 */
2673 
2674 /**
2675 * @name    query.offset
2676 * @description  Row number at which results should begin.
2677             Use this with maxRows to get pages of results.
2678 * @type   Integer
2679 */
2680 
2681 /**
2682 * @name   query.sort
2683 * @description	Sort specification. This can be a comma-delimited list of
2684             column names, where each column may have an optional dash (-) before the name
2685             to indicate a descending sort.
2686 * @type  String
2687 */
2688 
2689 /**
2690 * @name   maxRows
2691 * @description   Maximum number of rows to return
2692 * @type     Integer
2693 */
2694 
2695 /**
2696 * @name   filters
2697 * @description   An object whose properties are filter specifications, one for each filter you supplied.
2698  *          All filters are combined using AND logic. Each one is of type {@link LABKEY.Filter.FilterDefinition}.
2699  *          The list of valid operators:
2700             <ul><li><b>eq</b> = equals</li>
2701             <li><b>neq</b> = not equals</li>
2702             <li><b>gt</b> = greater-than</li>
2703             <li><b>gte</b> = greater-than or equal-to</li>
2704             <li><b>lt</b> = less-than</li>
2705             <li><b>lte</b> = less-than or equal-to</li>
2706             <li><b>dateeq</b> = date equal</li>
2707             <li><b>dateneq</b> = date not equal</li>
2708             <li><b>neqornull</b> = not equal or null</li>
2709             <li><b>isblank</b> = is null</li>
2710             <li><b>isnonblank</b> = is not null</li>
2711             <li><b>contains</b> = contains</li>
2712             <li><b>doesnotcontain</b> = does not contain</li>
2713             <li><b>startswith</b> = starts with</li>
2714             <li><b>doesnotstartwith</b> = does not start with</li>
2715             <li><b>in</b> = equals one of</li></ul>
2716 * @type    Object
2717 */
2718 
2719 /**#@-*/
2720 
2721 /**
2722 * @name LABKEY.Query.FieldMetaDataLookup
2723 * @class  Lookup metadata about a single field.
2724  *            <p>Additional Documentation:
2725  *              <ul>
2726  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2727  *                      How To Find schemaName, queryName & viewName</a></li>
2728  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
2729  *                      <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a></li>
2730  *              </ul>
2731  *           </p>
2732  * @see LABKEY.Query.FieldMetaData
2733 */
2734 
2735 /**#@+
2736 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2737 * @field
2738 * @name    containerPath
2739 * @description The path to the container that this lookup points to, if not the current container
2740 * @type    String
2741 */
2742 
2743 /**#@+
2744 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2745 * @field
2746 * @name    public
2747 * @description Whether the target of this lookup is exposed as a top-level query
2748 * @type    boolean
2749 */
2750 
2751 /**#@+
2752 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2753 * @field
2754 * @name queryName
2755 * @description The name of the query that this lookup targets
2756 * @type    String
2757 */
2758 
2759 /**#@+
2760 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2761 * @field
2762 * @name schemaName
2763 * @description The name of the schema that this lookup targets
2764 * @type    String
2765 */
2766 
2767 /**#@+
2768 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2769 * @field
2770 * @name keyColumn
2771 * @description The name of column in the lookup's target that will be joined to the value in the local field
2772 * @type    String
2773 */
2774 
2775 /**#@+
2776 * @memberOf LABKEY.Query.FieldMetaDataLookup#
2777 * @field
2778 * @name displayColumn
2779 * @description The name of the column in the lookup's target that will be shown as its value, instead of the raw key value
2780 * @type    String
2781 */
2782 
2783 /**#@-*/
2784 
2785 /**
2786 * @name LABKEY.Query.FieldMetaData
2787 * @class  Metadata about a single field.
2788  *            <p>Additional Documentation:
2789  *              <ul>
2790  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
2791  *                      How To Find schemaName, queryName & viewName</a></li>
2792  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
2793  *                      <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a></li>
2794  *              </ul>
2795  *           </p>
2796  * @see LABKEY.Query.selectRows
2797  * @see LABKEY.Query.getQueryDetails
2798 */
2799 
2800 /**#@+
2801 * @memberOf LABKEY.Query.FieldMetaData#
2802 * @field
2803 * @name    name
2804 * @description The name of the field
2805 * @type    String
2806 */
2807 
2808 /**#@+
2809 * @memberOf LABKEY.Query.FieldMetaData#
2810 * @field
2811 * @name    friendlyType
2812 * @description A friendlier, more verbose description of the type, like "Text (String)" or "Date and Time"
2813 * @type    String
2814 */
2815 
2816 /**#@+
2817 * @memberOf LABKEY.Query.FieldMetaData#
2818 * @field
2819 * @name    shownInInsertView
2820 * @description Whether this field is intended to be displayed in insert UIs
2821 * @type    boolean
2822 */
2823 
2824 /**#@+
2825 * @memberOf LABKEY.Query.FieldMetaData#
2826 * @field
2827 * @name    shownInDetailView
2828 * @description Whether this field is intended to be displayed in detail UIs
2829 * @type    boolean
2830 */
2831 
2832 /**#@+
2833 * @memberOf LABKEY.Query.FieldMetaData#
2834 * @field
2835 * @name    shownInUpdateView
2836 * @description Whether this field is intended to be displayed in update UIs
2837 * @type    boolean
2838 */
2839 
2840 /**#@+
2841 * @memberOf LABKEY.Query.FieldMetaData#
2842 * @field
2843 * @name    versionField
2844 * @description Whether this field's value stores version information for the row
2845 * @type    boolean
2846 */
2847 
2848 /**#@+
2849 * @memberOf LABKEY.Query.FieldMetaData#
2850 * @field
2851 * @name userEditable
2852 * @description Whether this field is intended to be edited directly by the user, or managed by the system
2853 * @type    boolean
2854 */
2855 
2856 /**#@+
2857 * @memberOf LABKEY.Query.FieldMetaData#
2858 * @field
2859 * @name calculated
2860 * @description Whether this field is a calculated value such as something generated by a SQL expression,
2861 * or a "real"/"physical" column in the database
2862 * @type    boolean
2863 */
2864 
2865 /**#@+
2866 * @memberOf LABKEY.Query.FieldMetaData#
2867 * @field
2868 * @name readOnly
2869 * @description Whether the field's value can be modified
2870 * @type    boolean
2871 */
2872 
2873 /**#@+
2874 * @memberOf LABKEY.Query.FieldMetaData#
2875 * @field
2876 * @name nullable
2877 * @description Whether the field's value is allowed to be null
2878 * @type    boolean
2879 */
2880 
2881 /**#@+
2882 * @memberOf LABKEY.Query.FieldMetaData#
2883 * @field
2884 * @name mvEnabled
2885 * @description Whether this field supports missing value indicators instead of or addition to its standard value
2886 * @type    boolean
2887 */
2888 
2889 /**#@+
2890 * @memberOf LABKEY.Query.FieldMetaData#
2891 * @field
2892 * @name keyField
2893 * @description Whether this field is part of the row's primary key
2894 * @type    boolean
2895 */
2896 
2897 /**#@+
2898 * @memberOf LABKEY.Query.FieldMetaData#
2899 * @field
2900 * @name hidden
2901 * @description Whether this value is intended to be hidden from the user, especially for grid views
2902 * @type    boolean
2903 */
2904 
2905 /**#@+
2906 * @memberOf LABKEY.Query.FieldMetaData#
2907 * @field
2908 * @name autoIncrement
2909 * @description Whether this field's value is automatically assigned by the server, like a RowId whose value is determined by a database sequence
2910 * @type    boolean
2911 */
2912 
2913 /**#@+
2914 * @memberOf LABKEY.Query.FieldMetaData#
2915 * @field
2916 * @name jsonType
2917 * @description The type of JSON object that will represent this field's value: string, boolean, date, int, or float
2918 * @type    String
2919 */
2920 
2921 /**#@+
2922 * @memberOf LABKEY.Query.FieldMetaData#
2923 * @field
2924 * @name importAliases
2925 * @description Alternate names for this field that may appear in data when importing, whose values should be mapped to this field
2926 * @type    String[]
2927 */
2928 
2929 /**#@+
2930 * @memberOf LABKEY.Query.FieldMetaData#
2931 * @field
2932 * @name tsvFormat
2933 * @description The format string to be used for TSV exports
2934 * @type    String
2935 */
2936 
2937 /**#@+
2938 * @memberOf LABKEY.Query.FieldMetaData#
2939 * @field
2940 * @name format
2941 * @description The format string to be used for generating HTML
2942 * @type    String
2943 */
2944 
2945 /**#@+
2946 * @memberOf LABKEY.Query.FieldMetaData#
2947 * @field
2948 * @name excelFormat
2949 * @description The format string to be used for Excel exports
2950 * @type    String
2951 */
2952 
2953 /**#@+
2954 * @memberOf LABKEY.Query.FieldMetaData#
2955 * @field
2956 * @name extFormat
2957 * @description The format string that can be passed to Ext components.  This is currently only supported for dates.
2958 * @type    String
2959 */
2960 
2961 /**#@+
2962 * @memberOf LABKEY.Query.FieldMetaData#
2963 * @field
2964 * @name extFormatFn
2965 * @description A function that can be used to produce the formatted string for this field.  This is currently supported for dates and numeric values.
2966 * Note: this function is returned as a string, so you will need to evaluate it to convert it to a function.  See example below.
2967 * @example <pre name="code" class="xml">
2968 * var formatFn = eval(meta.extFormatFn);
2969 * var formattedValue = formatFn(data);
2970 * </pre></code>
2971 *
2972 * @type    String
2973 */
2974 
2975 /**#@+
2976 * @memberOf LABKEY.Query.FieldMetaData#
2977 * @field
2978 * @name caption
2979 * @description The caption to be shown for this field, typically in a column header, which may differ from its name
2980 * @type    String
2981 */
2982 
2983 /**#@+
2984 * @memberOf LABKEY.Query.FieldMetaData#
2985 * @field
2986 * @name shortCaption
2987 * @description The caption for this field, without any prefix from potential parent lookups. In many cases this will be identical to the caption property.
2988 * @type    String
2989 */
2990 
2991 /**#@+
2992 * @memberOf LABKEY.Query.FieldMetaData#
2993 * @field
2994 * @name description
2995 * @description The description for this field
2996 * @type    String
2997 */
2998 
2999 /**#@+
3000 * @memberOf LABKEY.Query.FieldMetaData#
3001 * @field
3002 * @name inputType
3003 * @description The type of form input to be used when editing this field, such as select, text, textarea, checkbox, or file
3004 * @type    boolean
3005 */
3006 
3007 /**#@+
3008 * @memberOf LABKEY.Query.FieldMetaData#
3009 * @field
3010 * @name lookup
3011 * @description Information about this field's lookup configuration
3012 * @type    LABKEY.Query.FieldMetaDataLookup
3013 */
3014 
3015 /**#@-*/
3016 
3017 /**
3018 * @name LABKEY.Query.SelectRowsResults
3019 * @class  SelectRowsResults class to describe the first
3020             object passed to the successCallback function by
3021             {@link LABKEY.Query.selectRows}. This object's properties are useful for
3022             matching requests to responses, as HTTP requests are typically
3023             processed asynchronously.
3024  *            <p>Additional Documentation:
3025  *              <ul>
3026  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
3027  *                      How To Find schemaName, queryName & viewName</a></li>
3028  *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
3029  *                      <a href="https://www.labkey.org/wiki/home/Study/demo/page.view?name=reagentRequest">Demo</a></li>
3030  *              </ul>
3031  *           </p>
3032 * @see LABKEY.Query.selectRows
3033 */
3034 
3035 /**#@+
3036 * @memberOf LABKEY.Query.SelectRowsResults#
3037 * @field
3038 */
3039 
3040 /**
3041 * @name    schemaName
3042 * @description the name of the resultset's source schema.
3043 * @type    String
3044 */
3045 
3046 /**
3047 * @name    queryName
3048 * @description the name of the resultset's source query.  In some cases, such as an 'executeSql' call with 'saveInSession' set to true, the
3049  * query name may refer to temporary query that can be used to re-retrieve data for the duration of the user's session. 
3050 * @type    String
3051 */
3052 
3053 /**
3054 * @name    metaData
3055 * @description Contains type and lookup information about the columns in the resultset.
3056 * @type    Object
3057 */
3058 
3059 /**
3060 * @name    metaData.root
3061 * @description 	Name of the property containing rows ("rows"). This is mainly for the Ext grid component.
3062 * @type     String
3063 */
3064 
3065 /**
3066 * @name    metaData.totalProperty
3067 * @description 	Name of the top-level property
3068             containing the row count ("rowCount") in our case. This is mainly
3069             for the Ext grid component.
3070 * @type   String
3071 */
3072 
3073 /**
3074 * @name   metaData.sortInfo
3075 * @description  Sort specification in Ext grid terms.
3076             This contains two sub-properties, field and direction, which indicate
3077             the sort field and direction ("ASC" or "DESC") respectively.
3078 * @type   Object
3079 */
3080 
3081 /**
3082 * @name    metaData.id
3083 * @description  Name of the primary key column.
3084 * @type     String
3085 */
3086 
3087 /**
3088 * @name    metaData.fields
3089 * @description	Array of field information.
3090 * @type    LABKEY.Query.FieldMetaData[]
3091 */
3092 
3093 /**
3094 * @name    columnModel
3095 * @description   Contains information about how one may interact
3096             with the columns within a user interface. This format is generated
3097             to match the requirements of the Ext grid component. See
3098             <a href="http://extjs.com/deploy/ext-2.2.1/docs/?class=Ext.grid.ColumnModel">
3099             Ext.grid.ColumnModel</a> for further information.
3100 * @type  Object[]
3101 */
3102 
3103 /**
3104 * @name   rows
3105 * @description    An array of rows, each of which is a
3106             sub-element/object containing a property per column.
3107 * @type   Object[]
3108 */
3109 
3110 /**
3111 * @name rowCount
3112 * @description Indicates the number of total rows that could be
3113             returned by the query, which may be more than the number of objects
3114             in the rows array if the client supplied a value for the query.maxRows
3115             or query.offset parameters. This value is useful for clients that wish
3116             to display paging UI, such as the Ext grid.
3117 * @type   Integer
3118 */
3119 
3120 /**#@-*/
3121 
3122  /**
3123 * @name LABKEY.Query.ExtendedSelectRowsResults
3124 * @class  ExtendedSelectRowsResults class to describe the first
3125             object passed to the successCallback function by
3126             {@link LABKEY.Query.selectRows} if config.requiredVersion is set to "9.1".
3127   *            <p>Additional Documentation:
3128   *              <ul>
3129   *                  <li><a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=findNames">
3130   *                      How To Find schemaName, queryName & viewName</a></li>
3131   *              </ul>
3132   *           </p>
3133 * @see LABKEY.Query.selectRows
3134  */
3135 
3136 /**#@+
3137 * @memberOf LABKEY.Query.ExtendedSelectRowsResults#
3138 * @field
3139 */
3140 
3141 /**
3142 * @name    LABKEY.Query.ExtendedSelectRowsResults#metaData
3143 * @description Contains type and lookup information about the columns in the resultset.
3144 * @type    Object
3145 */
3146 
3147 /**
3148 * @name    LABKEY.Query.ExtendedSelectRowsResults#metaData.root
3149 * @description 	Name of the property containing rows ("rows"). This is mainly for the Ext grid component.
3150 * @type     String
3151 */
3152 
3153 /**
3154 * @name    LABKEY.Query.ExtendedSelectRowsResults#metaData.totalProperty
3155 * @description 	Name of the top-level property
3156             containing the row count ("rowCount") in our case. This is mainly
3157             for the Ext grid component.
3158 * @type   String
3159 */
3160 
3161 /**
3162 * @name   LABKEY.Query.ExtendedSelectRowsResults#metaData.sortInfo
3163 * @description  Sort specification in Ext grid terms.
3164             This contains two sub-properties, field and direction, which indicate
3165             the sort field and direction ("ASC" or "DESC") respectively.
3166 * @type   Object
3167 */
3168 
3169 /**
3170 * @name    LABKEY.Query.ExtendedSelectRowsResults#metaData.id
3171 * @description  Name of the primary key column.
3172 * @type     String
3173 */
3174 
3175 /**
3176 * @name    LABKEY.Query.ExtendedSelectRowsResults#metaData.fields
3177 * @description	Array of field information.
3178             Each field has the following properties:
3179             <ul><li><b>name</b> -- The name of the field</li>
3180             <li><b>type</b> -- JavaScript type name of the field</li>
3181             <li><b>shownInInsertView</b> -- whether this field is intended to be shown in insert views</li>
3182             <li><b>shownInUpdateView</b> -- whether this field is intended to be shown in update views</li>
3183             <li><b>shownInDetailsView</b> -- whether this field is intended to be shown in details views</li>
3184             <li><b>measure</b> -- whether this field is a measure.  Measures are fields that contain data subject to charting and other analysis.</li>
3185             <li><b>dimension</b> -- whether this field is a dimension.  Data dimensions define logical groupings of measures.</li>
3186             <li><b>hidden</b> -- whether this field is hidden and not normally shown in grid views</li>
3187             <li><b>lookup</b> -- If the field is a lookup, there will
3188                 be four sub-properties listed under this property:
3189                 schema, table, displayColumn, and keyColumn, which describe the schema, table, and
3190                 display column, and key column of the lookup table (query).</li></ul>
3191 * @type    Object[]
3192 */
3193 
3194 /**
3195 * @name    LABKEY.Query.ExtendedSelectRowsResults#columnModel
3196 * @description   Contains information about how one may interact
3197             with the columns within a user interface. This format is generated
3198             to match the requirements of the Ext grid component. See
3199             <a href="http://extjs.com/deploy/ext-2.2.1/docs/?class=Ext.grid.ColumnModel">
3200             Ext.grid.ColumnModel</a> for further information.
3201 * @type  String
3202 */
3203 
3204 /**
3205 * @name   LABKEY.Query.ExtendedSelectRowsResults#rows
3206 * @description    An array of rows, each of which is a
3207             sub-element/object containing an object per column. The
3208             object will always contain a property named "value" that is the
3209             column's value, but it may also contain other properties about
3210             that column's value. For example, if the column was setup to track
3211             missing value information, it will also contain a property named mvValue (which
3212             is the raw value that is considered suspect), and a property named
3213             mvIndicator, which will be the string MV indicator (e.g., "Q").
3214 * @type   Object[]
3215 */
3216 
3217 /**
3218 * @name LABKEY.Query.ExtendedSelectRowsResults#rowCount
3219 * @description Indicates the number of total rows that could be
3220             returned by the query, which may be more than the number of objects
3221             in the rows array if the client supplied a value for the query.maxRows
3222             or query.offset parameters. This value is useful for clients who wish
3223             to display paging UI, such as the Ext grid.
3224 * @type   Integer
3225 */
3226 
3227 /**#@-*/
3228 
3229 /** docs for methods defined in dom/Query.js - primarily here to ensure API docs get generated with combined core/dom versions */
3230 
3231 /**
3232  * Execute arbitrary LabKey SQL and export the results to Excel or TSV. After this method is
3233  * called, the user will be prompted to accept a file from the server, and most browsers will allow
3234  * the user to either save it or open it in an apporpriate application.
3235  * For more information, see the
3236  * <a href="https://www.labkey.org/wiki/home/Documentation/page.view?name=labkeySql">
3237  * LabKey SQL Reference</a>.
3238  *
3239  * @memberOf LABKEY.Query
3240  * @function
3241  * @static
3242  * @name exportSql
3243  * @param config An object which contains the following configuration properties.
3244  * @param {String} config.schemaName name of the schema to query.
3245  * @param {String} config.sql The LabKey SQL to execute.
3246  * @param {String} [config.format] The desired export format. May be either 'excel' or 'tsv'. Defaults to 'excel'.
3247  * @param {String} [config.containerPath] The path to the container in which the schema and query are defined,
3248  *       if different than the current container. If not supplied, the current container's path will be used.
3249  * @param {String} [config.containerFilter] One of the values of {@link LABKEY.Query.containerFilter} that sets
3250  *       the scope of this query. Defaults to containerFilter.current, and is interpreted relative to
3251  *       config.containerPath.
3252  */
3253