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