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) 2012-2019 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 Domain static class to retrieve and edit domain definitions.
 22  *
 23  *        <p>A domain is a collection of fields.  Each data type (e.g., Assays, Lists, Datasets, Sample Sets and
 24  *        Custom Protein Lists) provides specialized handling for the domains it
 25  *        defines.   The number of domains defined by a data type varies; for example, Assays
 26  *        define multiple domains (batch, run, etc.), while Lists
 27  *        and Datasets define only one domain each.</p>
 28  *
 29  *            <p>Additional Documentation:
 30  *              <ul>
 31  *                  <li><a href="https://www.labkey.org/Documentation/wiki-page.view?name=propertyFields">LabKey Dataset Domain Fields</a></li>
 32  *              </ul>
 33  *           </p>
 34 */
 35 LABKEY.Domain = new function()
 36 {
 37 
 38     function createDomain(success, failure, parameters, containerPath)
 39     {
 40         LABKEY.Ajax.request({
 41             url : LABKEY.ActionURL.buildURL("property", "createDomain.api", containerPath),
 42             method : 'POST',
 43             success: LABKEY.Utils.getCallbackWrapper(success),
 44             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
 45             jsonData : parameters,
 46             headers : {
 47                 'Content-Type' : 'application/json'
 48             }
 49         });
 50     }
 51 
 52     function getDomain(success, failure, parameters, containerPath)
 53     {
 54         LABKEY.Ajax.request({
 55             url : LABKEY.ActionURL.buildURL("property", "getDomain.api", containerPath),
 56             method : 'GET',
 57             success: LABKEY.Utils.getCallbackWrapper(success),
 58             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
 59             params : parameters
 60         });
 61     }
 62 
 63     function getDomainDetails(success, failure, parameters, containerPath)
 64     {
 65         LABKEY.Ajax.request({
 66             url : LABKEY.ActionURL.buildURL("property", "getDomainDetails.api", containerPath),
 67             method : 'GET',
 68             success: LABKEY.Utils.getCallbackWrapper(success),
 69             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
 70             params : parameters
 71         });
 72     }
 73 
 74     function saveDomain(success, failure, parameters, containerPath)
 75     {
 76         LABKEY.Ajax.request({
 77             url : LABKEY.ActionURL.buildURL("property", "saveDomain.api", containerPath),
 78             method : 'POST',
 79             success: LABKEY.Utils.getCallbackWrapper(success),
 80             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
 81             jsonData : parameters,
 82             headers : {
 83                 'Content-Type' : 'application/json'
 84             }
 85         });
 86     }
 87 
 88     function deleteDomain(success, failure, parameters, containerPath)
 89     {
 90         LABKEY.Ajax.request({
 91             url : LABKEY.ActionURL.buildURL("property", "deleteDomain.api", containerPath),
 92             method : 'POST',
 93             success: LABKEY.Utils.getCallbackWrapper(success),
 94             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
 95             jsonData : parameters,
 96             headers : {
 97                 'Content-Type' : 'application/json'
 98             }
 99         });
100     }
101 
102     function listDomains(success, failure, parameters, containerPath)
103     {
104         LABKEY.Ajax.request({
105             url : LABKEY.ActionURL.buildURL("property", "listDomains.api", containerPath),
106             method : 'GET',
107             success: LABKEY.Utils.getCallbackWrapper(success),
108             failure: LABKEY.Utils.getCallbackWrapper(failure, this, true),
109             params : parameters
110         });
111     }
112 
113     /** @scope LABKEY.Domain */
114     return {
115 
116         /**
117          * Create a new domain with the given kind, domainDesign, and options or
118          * specify a <a href='https://www.labkey.org/Documentation/wiki-page.view?name=domainTemplates'>domain template</a> to use for the domain creation.
119          * Not all domain kinds can be created through this API.  Currently supported domain kinds are:
120          * "IntList", "VarList", "SampleSet", "DataClass", "StudyDatasetDate", "StudyDatasetVisit", "Vocabulary".
121          *
122          * @param {Object} config An object which contains the following configuration properties.
123          * @param {Function} config.success Required success callback.
124          * @param {Function} [config.failure] Failure callback.
125          * @param {String} config.kind The domain kind to create. One of "IntList", "VarList", "SampleSet", or "DataClass".
126          * @param {String} config.domainName The name of the domain to create.
127          * @param {String} config.module The name of a module that contains the domain template group.
128          * @param {String} config.domainGroup The name of a domain template group.
129          * @param {String} config.domainTemplate The name of a domain template within the domain group.
130          * @param {Boolean} config.createDomain When using a domain template, create the domain.  Defaults to true.
131          * @param {Boolean} config.importData When using a domain template, import initial data associated in the template.  Defaults to true.
132          * @param {LABKEY.Domain.DomainDesign} config.domainDesign The domain design to save.
133          * @param {Object} [config.options] Arguments used to create the specific domain type.
134          * @param {String} [config.containerPath] The container path in which to create the domain.
135          * @example Create domain:
136 <pre name="code" class="xml">
137 LABKEY.Domain.create({
138   kind: "IntList",
139   domainDesign: {
140     name: "LookupCodes",
141     description: "integer key list",
142     fields: [{
143       name: "id", rangeURI: "int"
144     },{
145       name: "code",
146       rangeURI: "string", scale: 4
147     }]
148   },
149   options: {
150     keyName: "id"
151   }
152 });
153 </pre>
154          * @example Create domain from a <a href='https://www.labkey.org/Documentation/wiki-page.view?name=domainTemplates'>domain template</a>:
155 <pre name="code" class="xml">
156 LABKEY.Domain.create({
157   module: "mymodule",
158   domainGroup: "codes",
159   domainTemplate: "LookupCodes",
160   importData: false
161 });
162          </pre>
163          * @example Import the initial data from the domain template of a previously created domain:
164 <pre name="code" class="xml">
165 LABKEY.Domain.create({
166   module: "mymodule",
167   domainGroup: "codes",
168   domainTemplate: "LookupCodes",
169   createDomain: false,
170   importData: true
171 });
172 </pre>
173          */
174         create : function (config)
175         {
176             // new-style
177             if (typeof config === "object")
178             {
179                 createDomain(config.success, config.failure, config, config.containerPath);
180             }
181             // old-style
182             else if (arguments.length > 1)
183             {
184                 var success = arguments[0],
185                     failure = arguments[1],
186                     params = {},
187                     containerPath;
188 
189                 if ((arguments.length == 4 || arguments.length == 5) && typeof arguments[3] === "string")
190                 {
191                     params.domainGroup = arguments[2];
192                     params.domainTemplate = arguments[3];
193                     containerPath = arguments[4];
194                 }
195                 else
196                 {
197                     params.kind = arguments[2];
198                     params.domainDesign = arguments[3];
199                     params.options = arguments[4];
200                     containerPath = arguments[5];
201                 }
202 
203                 createDomain(success, failure, params, containerPath);
204             }
205         },
206 
207 	/**
208 	* This api is deprecated, use {@link LABKEY.Domain.getDomainDetails} instead.
209      * @param {Object} config An object which contains the following configuration properties.
210 	* @param {Function} config.success Required. Function called if the
211 	*	"get" function executes successfully. Will be called with the argument {@link LABKEY.Domain.DomainDesign},
212     *    which describes the fields of a domain.
213 	* @param {Function} [config.failure] Function called if execution of the "get" function fails.
214 	* @param {String} config.schemaName Name of the schema
215 	* @param {String} config.queryName Name of the query
216     * @param {String} config.domainId Id of the domain. This is an alternate way to identify the domain.
217     *       SchemaName and queryName will be ignored if this value is not undefined or null.
218 	* @param {String} [config.containerPath] The container path in which the requested Domain is defined.
219 	*       If not supplied, the current container path will be used.
220 	* @example Example:
221 <pre name="code" class="xml">
222 <script type="text/javascript">
223 	function successHandler(domainDesign)
224 	{
225 		var html = '';
226 
227 		html += '<b>' + domainDesign.name + ':</b><br> ';
228 		for (var i in domainDesign.fields)
229 		{
230 			html += '   ' + domainDesign.fields[i].name + '<br>';
231 		}
232 		document.getElementById('testDiv').innerHTML = html;
233 	}
234 
235 	function errorHandler(error)
236 	{
237 		alert('An error occurred retrieving data: ' + error);
238 	}
239 
240 	LABKEY.Domain.get(successHandler, errorHandler, 'study', 'StudyProperties');
241 </script>
242 <div id='testDiv'>Loading...</div>
243 </pre>
244 	  * @see LABKEY.Assay.AssayDesign
245 	  */
246         get : function(config)
247         {
248             if (arguments.length > 1)
249             {
250                 config = {
251                     success: arguments[0],
252                     failure: arguments[1],
253                     schemaName: arguments[2],
254                     queryName: arguments[3],
255                     containerPath: arguments[4]
256                 };
257             }
258 
259             getDomain(
260                 config.success,
261                 config.failure,
262                 {schemaName: config.schemaName, queryName: config.queryName, domainId: config.domainId},
263                 config.containerPath);
264         },
265 
266     /**
267      * Gets a domain design along with domain kind specific properties.
268      * @param {Object} config An object which contains the following configuration properties.
269      * @param {Function} config.success Required. Function called if the
270      *    "getDomainDetails" function executes successfully. Will be called with the argument {@link LABKEY.Domain.DomainDesign},
271      *    which describes the fields of a domain.
272      * @param {Function} [config.failure] Function called if execution of the "getDomainDetails" function fails.
273      * @param {String} config.schemaName Name of the schema
274      * @param {String} config.queryName Name of the query
275      * @param {String} config.domainId Id of the domain. This is an alternate way to identify the domain.
276      *       SchemaName and queryName will be ignored if this value is not undefined or null.
277      * @param {String} [config.containerPath] The container path in which the requested Domain is defined.
278      *       If not supplied, the current container path will be used.
279      * @example Example:
280 <pre name="code" class="xml">
281 <script type="text/javascript">
282      function successHandler(domainDesign)
283      {
284         var html = '';
285 
286         html += '<b>' + domainDesign.name + ':</b><br> ';
287         for (var i in domainDesign.fields)
288         {
289             html += '   ' + domainDesign.fields[i].name + '<br>';
290         }
291         document.getElementById('testDiv').innerHTML = html;
292      }
293 
294      function errorHandler(error)
295      {
296         alert('An error occurred retrieving data: ' + error);
297      }
298 
299     LABKEY.Domain.getDomainDetails(successHandler, errorHandler, 'study', 'StudyProperties');
300 </script>
301 <div id='testDiv'>Loading...</div>
302 </pre>
303      * @see LABKEY.Assay.AssayDesign
304      */
305         getDomainDetails : function(config)
306         {
307             if (arguments.length > 1)
308             {
309                 config = {
310                     success: arguments[0],
311                     failure: arguments[1],
312                     schemaName: arguments[2],
313                     queryName: arguments[3],
314                     containerPath: arguments[4]
315                 };
316             }
317 
318             getDomainDetails(
319                     config.success,
320                     config.failure,
321                     {schemaName: config.schemaName, queryName: config.queryName, domainId: config.domainId},
322                     config.containerPath);
323         },
324 
325         /**
326          * Lists all the domains within a given container. Specify domain kinds to get the targeted list of domain kinds.
327          * @param {Object} config An object which contains the following configuration properties.
328          * @param {Function} config.success Required success callback.
329          * @param {Function} [config.failure] Failure callback.
330          * @param {Boolean} config.includeFields Include Fields of in the list of domains. Defaults to false.
331          * @param {Boolean} config.includeProjectAndShared Includes domains in projects and shared. Defaults to false.
332          * @param {Array} config.domainKinds The list of domain Kinds to include in the list. Defaults to all the domains in container.
333          * @param {String} config.containerPath Container path of the domains holding container.
334          * @example List domains:
335          <pre name="code" class="xml">
336  LABKEY.Domain.listDomains({
337   includeFields: "true",
338   domainKinds: ["ExtensibleTable", "Vocabulary"]
339 });
340          </pre>
341          */
342         listDomains : function(config)
343         {
344             var params = {
345                 includeFields: config.includeFields,
346                 includeProjectAndShared: config.includeProjectAndShared
347             };
348 
349             if (config.domainKinds)
350                 params.domainKinds = config.domainKinds;
351 
352             listDomains(
353                     config.success,
354                     config.failure,
355                     params,
356                     config.containerPath);
357         },
358 
359         /**
360          * Saves the provided domain design.
361          * Note: All of the domain properties are expected to be present before saving, and not just the diff - the easiest way
362          * is to get the existing domain via {@Link LABKEY.Domain.getDomainDetails} and update the resultant json with your changes before saving.
363          * @param {Object} config An object which contains the following configuration properties.
364          * @param {Function} config.success Required. Function called if this
365                   function executes successfully. No parameters will be passed to the success callback.
366          * @param {Function} [config.failure] Function called if execution of this function fails.
367          * @param {LABKEY.Domain.DomainDesign} config.domainDesign The domain design to save.
368          * @param {String} config.schemaName Name of the schema
369          * @param {String} config.queryName Name of the query
370          * @param {String} config.domainId Id of the domain. This is an alternate way to identify the domain to update.
371          *        SchemaName and queryName will be ignored if this value is not undefined or null.
372          * @param {String} [config.containerPath] The container path in which the requested Domain is defined.
373          *       If not supplied, the current container path will be used.
374          * @param {boolean} config.includeWarnings set this to true, if server side warnings are desired along with the errors
375          *       If this is set to true and there are warnings detected, they will prevent the save from completing successfully
376          * @param {Object} [config.options] Domain Kind specific properties.
377          *       If not supplied, will be ignored.
378          *       Note: Certain domain kind specific properties are read-only and cannot be updated.
379          *       Read-only properties for 'IntList' & 'VarList' domain kinds: listId, domainId, keyName, keyType, and lastIndexed.
380          */
381         save : function(config)
382         {
383             if (arguments.length > 1)
384             {
385                 config = {
386                     success: arguments[0],
387                     failure: arguments[1],
388                     domainDesign: arguments[2],
389                     schemaName: arguments[3],
390                     queryName: arguments[4],
391                     containerPath: arguments[5],
392                     includeWarnings: arguments[6],
393                     options: arguments[7]
394                 };
395             }
396 
397             saveDomain(
398                 config.success,
399                 config.failure,
400                 {domainDesign: config.domainDesign, schemaName: config.schemaName, queryName: config.queryName,
401                     domainId: config.domainId, includeWarnings: config.includeWarnings, options: config.options},
402                 config.containerPath);
403         },
404 
405         /**
406          * Delete a domain.
407          *
408          * @param config
409          * @param {Object} config An object which contains the following configuration properties.
410          * @param {Function} config.success.
411          * @param {Function} [config.failure]
412          * @param {String} config.schemaName Name of the schema
413          * @param {String} config.queryName Name of the query
414          * @param {String} [config.containerPath] The container path in which the requested Domain is defined.
415          *       If not supplied, the current container path will be used.
416          */
417         drop : function (config)
418         {
419             deleteDomain(
420                 config.success,
421                 config.failure,
422                 {domainDesign: config.domainDesign, schemaName: config.schemaName, queryName: config.queryName},
423                 config.containerPath);
424         },
425 
426         /**
427          * Get property descriptor information.
428          * @param {Object} config An object which contains the following configuration properties.
429          * @param {Function} [config.success] Success callback is a function that is called with an array of property information in the same format as 'fields' within {@link LABKEY.Domain.DomainDesign}.
430          * @param {Function} [config.failure] Failure callback.
431          * @param {Array} config.propertyIds Array of integer propertyIds.
432          * @param {Array} config.propertyURIs Array of string propertyURIs.
433          * @param {String} config.containerPath Container path of the property definitions.
434          */
435         getProperties : function (config)
436         {
437             var parameters = {};
438             if (config.propertyIds)
439                 parameters.propertyIds = config.propertyIds;
440 
441             if (config.propertyURIs)
442                 parameters.propertyURIs = config.propertyURIs;
443 
444             LABKEY.Ajax.request({
445                 url: LABKEY.ActionURL.buildURL("property", "getProperties.api", config.containerPath, parameters),
446                 success: LABKEY.Utils.getCallbackWrapper(config.success),
447                 failure: LABKEY.Utils.getCallbackWrapper(config.failure, this, true)
448             });
449         }
450     };
451 
452 
453 };
454 
455 /**
456 * @name LABKEY.Domain.DomainDesign
457 * @class  DomainDesign static class to describe the shape and fields of a domain.  The {@link LABKEY.Domain}
458 *             'getDomainDetails' and 'save' methods employ DomainDesign.
459 */
460 
461 /**#@+
462 * @memberOf LABKEY.Domain.DomainDesign#
463 * @field
464 */
465 
466 /**
467 * @name name
468 * @description   The name of this domain.
469 * @type String
470 */
471 
472 /**
473 * @name domainId
474 * @description The unique ID of this domain.
475 * @type Integer
476 */
477 
478 /**
479 * @name description
480 * @description  The description of this domain.
481 * @type String
482 */
483 
484 /**
485 * @name domainURI
486 * @description  The URI of this domain.
487 * @type String
488 */
489 
490 /**
491 * @name fields
492 * @description An array of objects that each describe a domain field.  Each object has the following properties:
493     *       (Note: Not all properties below are expected to have values or will have values. See {@Link LABKEY.Domain} 'Create' to see minimally required properties when creating a Domain.)
494     *      <ul>
495     *          <li><b>propertyId:</b> The unique ID of this field. (integer)</li>
496     *          <li><b>propertyURI:</b> The URI of this field. (string)</li>
497     *          <li><b>ontologyURI:</b> The URI of the ontology this field belongs to. (string)</li>
498     *          <li><b>name:</b> The name of this field. (string)</li>
499     *          <li><b>description:</b> The description of this field (may be blank). (string)</li>
500     *          <li><b>rangeURI:</b> The URI for this field's range definition. (string)</li>
501     *          <li><b>conceptURI:</b> The URI of this field's concept. (string)</li>
502     *          <li><b>label:</b> The friendly label for this field. (string)</li>
503     *          <li><b>searchTerms:</b> The search terms for this field. (string)</li>
504     *          <li><b>semanticType:</b> The semantic type of this field. (string)</li>
505     *          <li><b>format:</b> The format string defined for this field. (string)</li>
506     *          <li><b>required:</b> Indicates whether this field is required to have a value (i.e. cannot be null). (boolean)</li>
507     *          <li><b>lookupContainer:</b> If this domain field is a lookup, this holds the container in which to look. (string)</li>
508     *          <li><b>lookupSchema:</b> If this domain field is a lookup, this holds the schema in which to look. (string)</li>
509     *          <li><b>lookupQuery:</b> if this domain field is a lookup, this holds the query in which to look. (string)</li>
510     *          <li><b>defaultDisplayValue:</b> Default value to display. (string)</li>
511     *          <li><b>defaultValue:</b> Default value for the field. (string)</li>
512     *          <li><b>defaultValueType:</b> Default value type for the field. (string)</li>
513     *          <li><b>hidden:</b> Indicates whether this field is to be hidden or shown in a view. (boolean)</li>
514     *          <li><b>isPrimaryKey:</b> Indicates whether this field is a Primary Key. (boolean)</li>
515     *          <li><b>lockType:</b> Set lock level on this field. Expected value should be one of: "NotLocked"
516     *              (can change all properties, this is default) or "PartiallyLocked" (can't change name and type property) or "FullyLocked" (can't change any of the properties). (string)</li>
517     *          <li><b>phi:</b> Set PHI level on this field. Expected value should be one of: "NotPhi" (default) or "Limited" or "PHI" or "Restricted". (string)</li>
518     *          <li><b>scale:</b> Scale for the field. (int)</li>
519     *          <li><b>shownInDetailsView:</b> Indicates whether this field is to be shown in Details view. (boolean)</li>
520     *          <li><b>shownInInsertView:</b> Indicates whether this field is to be shown in an Insert view. (boolean)</li>
521     *          <li><b>shownInUpdateView:</b> Indicates whether this field is to be shown in an Update view. (boolean)</li>
522     *          <li><b>url:</b> A url associated with this field. (string)</li>
523     *      </ul>
524     * @type Object
525 */
526 
527 /**
528  * @name indices
529  * @description An array of objects that each designate an index upon the domain.  Each object has the following properties:
530  *      <ul>
531  *          <li><b>columnNames:</b> An array of strings, where each string is the name of a domain field that will be an index. (array)</li>
532  *          <li><b>unique:</b> Indicates whether the domain field is allowed to contain any duplicate values. (boolean)</li>
533  *      </ul>
534  * @type Object
535  */
536 
537 /**#@-*/
538