      1 /*
      2  *  Copyright (C) 2008-2009 WaveMaker Software, Inc.
      3  *
      4  *  This file is part of the WaveMaker Client Runtime.
      5  *
      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  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0
     11  *
     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  */
     18 dojo.provide('wm.base.lib.data');
     19
     20 wm.data = wm.data || {};
     21
     22 dojo.mixin(wm.data, {
     23 	// returns fields that should be included for type
     24 	getIncludeFields: function(inTypeName) {
     25 		var
     26 			pi, fields=[],
     27 			schema = wm.typeManager.getTypeSchema(inTypeName);
     28 		for (var i in schema) {
     29 			pi = schema[i];
     30 			if (pi.include && pi.include.length) {
     31 				// composite key
     32 				if (wm.typeManager.isStructuredType(pi.type)) {
     33 					var compSchema = wm.typeManager.getTypeSchema(pi.type);
     34 					for (var j in compSchema)
     35 						fields.push(i + "." + j);
     36 				} else
     37 					fields.push(i);
     38 			}
     39 		}
     40 		return fields;
     41 	},
     42 	// Reports if given data of type has include data.
     43 	// This is equivalent to having primary key information
     44 	// that is necessary for initiating update and delete operations.
     45 	// By default related structured types are not checked for include data
     46 	// That information is typically not required for update / delete operations.
     47 	hasIncludeData: function(inTypeName, inData) {
     48 		if (!inData || wm.isEmpty(inData))
     49 			return false;
     50 		var fields = this.getIncludeFields(inTypeName);
     51 		for (var i=0, f; f=fields[i]; i++)
     52 			if (dojo.getObject(f, false, inData) === undefined)
     53 				return;
     54 		return true;
     55 	},
     56 	// Reports if given data of type contains necessary contents
     57 	// to perform given operation.
     58 	hasOperationData: function(inOperation, inTypeName, inData) {
     59 		if (!wm.typeManager.getLiveService(inTypeName))
     60 			return false;
     61 		switch(inOperation) {
     62 			// read ok if we provide no data or we have necessary root include data
     63 			case "read":
     64 				return !inData || wm.data.hasIncludeData(inTypeName, inData);
     65 			// root include data is required for delete and update
     66 			case "delete":
     67 			case "update":
     68 				return wm.data.hasIncludeData(inTypeName, inData);
     69 			// for insert all required root and provided related required data is necessary
     70 			case "insert":
     71 				return wm.data.hasRequiredData(inOperation, inTypeName, inData, true);
     72 		}
     73 	},
     74 	// Reports if given data of type contains all required data
     75 	// This info is helpful for determining if there's enough data to perform an insert operation
     76 	// In this case we want to check structured related data also.
     77 	// Operation and the structured data flag are provided for additional flexibility...
     78 	hasRequiredData: function(inOperation, inTypeName, inData, inCheckStructured) {
     79 		var schema = wm.typeManager.getTypeSchema(inTypeName),
     80 			s, d, isStructured, hasData, missingRequired, hasExcluded;
     81 		for (var i in schema) {
     82 			s = schema[i];
     83 			isStructured = wm.typeManager.isStructuredType(s.type);
     84 			d = inData && inData[i];
     85 			// check structured type
     86 			if (isStructured && inCheckStructured) {
     87 				if ((d || s.required) && !s.isList && !this.hasRequiredData(s.type, d, inCheckStructured))
     88 					return false;
     89 			} else {
     90 				hasData = (d !== undefined);
     91 				missingRequired = s.required && !hasData;
     92 				// return false if we have excluded data or missing required data.
     93 				if (dojo.indexOf(s.exclude, inOperation) != -1 ? hasData : missingRequired)
     94 					return false;
     95 			}
     96 		}
     97 		return true;
     98 	},
     99 	// binding
    100 	clearBinding: function(inObject, inTargetProperty) {
    101 		var w = wm.data.getPropWire(inObject, inTargetProperty);
    102 		if (w) {
    103 			var b = w.owner, target = w.target, tp = w.targetProperty;
    104 			// note: removing wire may have side-effects so reset value with care after removing.
    105 			if (b)
    106 				b.removeWire(w.getWireId());
    107 			// reset value here.
    108 			if (target && tp)
    109 				target.setValue(tp, "");
    110 		}
    111 	},
    112 	getPropWire: function(inTargetObject, inTargetProperty) {
    113 		var
    114 			tp = inTargetProperty,
    115 			tobj = inTargetObject,
    116 			binding = tobj && tobj.$.binding,
    117 			// Note: target bindings are stored in wires hash by targetProperty
    118 			// source bindings has targetId appended so they will be ignored below
    119 			w = binding && binding.wires[tp];
    120 		// if there's a target binding, return it
    121 		if (w)
    122 			return w;
    123 		// FIXME: design check...
    124 		var ownerApp = tobj && tobj.isDesignLoaded() ? studio.application : app;
    125 		// otherwise, if the object is owned by the application try to return a source binding.
    126 		if (tobj && tobj.isOwnedBy(ownerApp))
    127 			return wm.data.findSourceWire((tobj||0).getId(), tp);
    128 	},
    129 	findSourceWire: function(inTargetId, inProp) {
    130 		if (inTargetId) {
    131 			var c, o, id, wires, w;
    132 			// search all components, wee...
    133 			for (var i in wm.Component.byId) {
    134 				c = wm.Component.byId[i];
    135 				// FIXME: design check...
    136 				if ((c instanceof wm.Binding) && (c.isDesignLoaded() || !(window.studio && window.studio._isWaveMakerStudio))) {
    137 					var wires = c.findWiresByProps({targetId: inTargetId, targetProperty: inProp});
    138 					if (wires.length)
    139 						return wires[0];
    140 				}
    141 			}
    142 		}
    143 	},
    144 	// FIXME: deprecated
    145 	/*getPropertyBindWire: function(inBinding, inTargetProperty) {
    146 		var wires = inBinding.wires, w;
    147 		for (var i in wires) {
    148 			w = wires[i];
    149 			if (w.targetProperty == inTargetProperty)
    150 				return w;
    151 		}
    152 	},*/
    153 	getPropBindSource: function(inTargetObject, inTargetProperty) {
    154 		var w = wm.data.getPropWire(inTargetObject, inTargetProperty);
    155 		if (w)
    156 			return inTargetObject.getValueById(w.source);
    157 	},
    158 	// a simple comparator
    159 	compare: function(a, b) {
    160 		return a === b ? 0 :
    161 			a === undefined ? -1 :
    162 			b === undefined ? 1 :
    163 			b === null ? 1 :
    164 			a > b ? 1 :
    165 			-1;
    166 	}
    167 });