Example #1
0
/*
 * Adapted version of node.extend https://www.npmjs.org/package/node.extend
 *
 * Original copyright:
 *
 * node.extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */
function deepExtend() {
	var target = arguments[0] || {};
	var i = 1;
	var length = arguments.length;
	var deep = false;
	var options, name, src, copy, copy_is_array, clone;

	// Handle a deep copy situation
	if (typeof target === 'boolean') {
		deep = target;
		target = arguments[1] || {};
		// skip the boolean and the target
		i = 2;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if (typeof target !== 'object' && !_.isFunction(target)) {
		target = {};
	}

	for (; i < length; i++) {
		// Only deal with non-null/undefined values
		options = arguments[i]
		if (options != null) {
			if (typeof options === 'string') {
					options = options.split('');
			}
			// Extend the base object
			for (name in options) {
				src = target[name];
				copy = options[name];

				// Prevent never-ending loop
				if (target === copy) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if (deep && copy && ((_.isObject(copy) && !_.has(copy, 'apiName')) || (copy_is_array = _.isArray(copy)))) {
					if (copy_is_array) {
						copy_is_array = false;
						clone = src && _.isArray(src) ? src : [];
					} else {
						clone = src && _.isObject(src) ? src : {};
					}

					// Never move original objects, clone them
					target[name] = deepExtend(deep, clone, copy);

				// Don't bring in undefined values
				} else if (typeof copy !== 'undefined') {
					target[name] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};
Example #2
0
function deepExtend() {
    var target = arguments[0] || {};
    var i = 1;
    var length = arguments.length;
    var deep = false;
    var options, name, src, copy, copy_is_array, clone;
    if ("boolean" == typeof target) {
        deep = target;
        target = arguments[1] || {};
        i = 2;
    }
    "object" == typeof target || _.isFunction(target) || (target = {});
    for (;length > i; i++) {
        options = arguments[i];
        if (null != options) {
            "string" == typeof options && (options = options.split(""));
            for (name in options) {
                src = target[name];
                copy = options[name];
                if (target === copy) continue;
                if (deep && copy && _.isObject(copy) && ((copy_is_array = _.isArray(copy)) || !_.has(copy, "apiName"))) {
                    if (copy_is_array) {
                        copy_is_array = false;
                        clone = src && _.isArray(src) ? src : [];
                    } else clone = _.isDate(copy) ? new Date(copy.valueOf()) : src && _.isObject(src) ? src : {};
                    target[name] = deepExtend(deep, clone, copy);
                }
                target[name] = copy;
            }
        }
    }
    return target;
}
Example #3
0
exports.createStyle = function(controller, opts, defaults) {
    var classes, apiName;
    if (!opts) return {};
    classes = _.isArray(opts.classes) ? opts.classes.slice(0) : _.isString(opts.classes) ? opts.classes.split(/\s+/) : [];
    apiName = opts.apiName;
    apiName && -1 === apiName.indexOf(".") && (apiName = addNamespace(apiName));
    var styleArray;
    styleArray = controller && _.isObject(controller) ? require("alloy/widgets/" + controller.widgetId + "/styles/" + controller.name) : require("alloy/styles/" + controller);
    var styleFinal = {};
    var i, len;
    for (i = 0, len = styleArray.length; len > i; i++) {
        var style = styleArray[i];
        var styleApi = style.key;
        style.isApi && -1 === styleApi.indexOf(".") && (styleApi = (CONST.IMPLICIT_NAMESPACES[styleApi] || CONST.NAMESPACE_DEFAULT) + "." + styleApi);
        if (style.isId && opts.id && style.key === opts.id || style.isClass && _.contains(classes, style.key)) ; else {
            if (!style.isApi) continue;
            -1 === style.key.indexOf(".") && (style.key = addNamespace(style.key));
            if (style.key !== apiName) continue;
        }
        if (style.queries && style.queries.formFactor && !Alloy[style.queries.formFactor]) continue;
        _.extend(styleFinal, style.style);
    }
    var extraStyle = _.omit(opts, [ CONST.CLASS_PROPERTY, CONST.APINAME_PROPERTY ]);
    _.extend(styleFinal, extraStyle);
    styleFinal[CONST.CLASS_PROPERTY] = classes;
    styleFinal[CONST.APINAME_PROPERTY] = apiName;
    return defaults ? _.defaults(styleFinal, defaults) : styleFinal;
};
Example #4
0
exports.createWidget = function(id, name, args) {
    if ("undefined" != typeof name && null !== name && _.isObject(name) && !_.isString(name)) {
        args = name;
        name = DEFAULT_WIDGET;
    }
    return new (require("alloy/widgets/" + id + "/controllers/" + (name || DEFAULT_WIDGET)))(args);
};
Example #5
0
 function updateSQL(data) {
     var attrObj = {};
     if (DEBUG) {
         Ti.API.debug("updateSQL data:");
         Ti.API.debug(data);
     }
     data ? attrObj = data : isCollection ? Ti.API.error("Its a collection - error!") : attrObj = model.toJSON();
     var names = [], values = [], q = [];
     for (var k in columns) if (!_.isUndefined(attrObj[k])) {
         names.push(k + "=?");
         _.isObject(attrObj[k]) ? values.push(JSON.stringify(attrObj[k])) : values.push(attrObj[k]);
         q.push("?");
     }
     var sql = "UPDATE " + table + " SET " + names.join(",") + " WHERE " + model.idAttribute + "=?";
     values.push(attrObj[model.idAttribute]);
     if (DEBUG) {
         Ti.API.debug("updateSQL sql: " + sql);
         Ti.API.debug(values);
     }
     db = Ti.Database.open(dbName);
     db.execute(sql, values);
     if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
         var updateSQL = "UPDATE " + table + " SET " + lastModifiedColumn + " = DATETIME('NOW') WHERE " + model.idAttribute + "=?";
         db.execute(updateSQL, attrObj[model.idAttribute]);
     }
     db.close();
     return attrObj;
 }
Example #6
0
exports.createWidget = function(id, name, args) {
	if (typeof name !== 'undefined' && name !== null &&
		_.isObject(name) && !_.isString(name)) {
		args = name;
		name = DEFAULT_WIDGET;
	}
	return new (require('alloy/widgets/' + id + '/controllers/' + (name || DEFAULT_WIDGET)))(args);
};
Example #7
0
 _.each(data, function(v, f) {
     if (_.isArray(v)) {
         var innerWhere = [];
         _.each(v, function(value) {
             innerWhere.push(f + " = " + _valueType(value));
         });
         where.push(innerWhere.join(" OR "));
     } else _.isObject(v) ? where = whereBuilder(where, v) : where.push(f + " = " + _valueType(v));
 });
Example #8
0
  function updateSQL(data, queryList) {
    var attrObj = {};

    logger(DEBUG, "updateSQL data: ", data);

    if (data) {
      attrObj = data;
    } else {
      if (!isCollection) {
        attrObj = model.toJSON();
      } else {
        Ti.API.error("Its a collection - error!");
      }
    }

    // Create arrays for insert query
    var names = [],
      values = [],
      q = [];
    for (var k in columns) {
      if (!_.isUndefined(attrObj[k])) {//only update those who are in the data
        names.push(k + '=?');
        if (_.isObject(attrObj[k])) {
          values.push(JSON.stringify(attrObj[k]));
        } else {
          values.push(attrObj[k]);
        }
        q.push('?');
      }
    }

    if (params.lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
      values[_.indexOf(names, params.lastModifiedColumn + "=?")] = params.lastModifiedDateFormat ? moment().format(params.lastModifiedDateFormat) : moment().lang('en').zone('GMT').format('YYYY-MM-DD HH:mm:ss ZZ');
    }

    // compose the update query
    var sql = 'UPDATE ' + table + ' SET ' + names.join(',') + ' WHERE ' + model.idAttribute + '=?';
    values.push(attrObj[model.idAttribute]);

    logger(DEBUG, "updateSQL sql query: " + sql);
    logger(DEBUG, "updateSQL values: ", values);

    if (queryList) {
      queryList.push({
        "sql" : sql,
        "values" : values
      });
      return queryList;
    } else {
      // execute the update
      db = Ti.Database.open(dbName);
      db.execute(sql, values);
      db.close();
    }

    return attrObj;
  }
Example #9
0
	function deleteBasedOnSQL(obj) {
		if (!_.isObject(obj)) {
			Ti.API.error("[SQL REST API] deleteBasedOnSQL :: Error no object provided");
			return;
		}
		var sql = _buildQuery(table, obj, "DELETE");
		db = Ti.Database.open(dbName);
		db.execute(sql);
		db.close();
	}
Example #10
0
exports.createController = function(name, args) {
	var newController = new (require('alloy/controllers/' + name))(args);
	if(args && args.autoView && _.isObject(args.autoView)) {
		_.each(args.autoView, function(props, id) {
			if(newController[id]) {
				_.each(props, function(val, key) {
					newController[id][key] = val;
				});
			}
		});
	}
	return newController;
};
Example #11
0
PiwikApiRequest.prototype.getErrorIfInvalidResponse = function (response) {
    var _ = require('alloy/underscore')._;
    
    if (response && _.isObject(response) && response.result && 'error' == response.result) {
        // the piwik response contains an error

        return response.message + '';
    }
    
    response = null;
    
    return null;
};
Example #12
0
	_.each(data, function(v, f) {
		if (_.isArray(v)) {//select multiple items
			var innerWhere = [];
			_.each(v, function(value) {
				innerWhere.push(f + " = " + _valueType(value));
			});
			where.push(innerWhere.join(' OR '));
		} else if (_.isObject(v)) {
			where = whereBuilder(where, v);
		} else {
			where.push(f + " = " + _valueType(v));
		}
	});
Example #13
0
	function updateSQL(data) {
		var attrObj = {};
		if (DEBUG) {
			Ti.API.debug("updateSQL data:");
			Ti.API.debug(data);
		}
		if (data) {
			attrObj = data;
		} else {
			if (!isCollection) {
				attrObj = model.toJSON();
			} else {
				Ti.API.error("Its a collection - error!");
			}
		}

		// Create arrays for insert query
		var names = [], values = [], q = [];
		for (var k in columns) {
			if (!_.isUndefined(attrObj[k])) {//only update those who are in the data
				names.push(k + '=?');
				if (_.isObject(attrObj[k])) {
					values.push(JSON.stringify(attrObj[k]));
				} else {
					values.push(attrObj[k]);
				}
				q.push('?');
			}
		}

		// compose the update query
		var sql = 'UPDATE ' + table + ' SET ' + names.join(',') + ' WHERE ' + model.idAttribute + '=?';
		values.push(attrObj[model.idAttribute]);
		if (DEBUG) {
			Ti.API.debug("updateSQL sql: " + sql);
			Ti.API.debug(values);
		}
		// execute the update
		db = Ti.Database.open(dbName);
		db.execute(sql, values);
		
		if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
			var updateSQL = "UPDATE " + table + " SET " + lastModifiedColumn + " = DATETIME('NOW') WHERE " + model.idAttribute + "=?";
			db.execute(updateSQL, attrObj[model.idAttribute]);
		}

		db.close();

		return attrObj;
	}
Example #14
0
 function createSQL(data) {
     var attrObj = {};
     if (DEBUG) {
         Ti.API.debug("[SQL REST API] createSQL data:");
         Ti.API.debug(data);
     }
     data ? attrObj = data : isCollection ? Ti.API.error("[SQL REST API] Its a collection - error !") : attrObj = model.toJSON();
     if (!attrObj[model.idAttribute]) if (model.idAttribute === ALLOY_ID_DEFAULT) {
         attrObj.id = guid();
         attrObj[model.idAttribute] = attrObj.id;
     } else attrObj[model.idAttribute] = null;
     if (useStrictValidation) for (var c in columns) {
         if (c == model.idAttribute) continue;
         if (!_.contains(_.keys(attrObj), c)) {
             Ti.API.error("[SQL REST API] ITEM NOT VALID - REASON: " + c + " is not present");
             return;
         }
     }
     var names = [], values = [], q = [];
     for (var k in columns) {
         names.push(k);
         _.isObject(attrObj[k]) ? values.push(JSON.stringify(attrObj[k])) : values.push(attrObj[k]);
         q.push("?");
     }
     lastModifiedColumn && _.isUndefined(params.disableLastModified) && (values[_.indexOf(names, lastModifiedColumn)] = lastModifiedDateFormat ? moment().format(lastModifiedDateFormat) : moment().format("YYYY-MM-DD HH:mm:ss"));
     var sqlInsert = "INSERT INTO " + table + " (" + names.join(",") + ") VALUES (" + q.join(",") + ");";
     db = Ti.Database.open(dbName);
     db.execute("BEGIN;");
     db.execute(sqlInsert, values);
     if (null === model.id) {
         var sqlId = "SELECT last_insert_rowid();";
         var rs = db.execute(sqlId);
         if (rs.isValidRow()) {
             model.id = rs.field(0);
             attrObj[model.idAttribute] = model.id;
         } else Ti.API.warn("Unable to get ID from database for model: " + model.toJSON());
     }
     db.execute("COMMIT;");
     db.close();
     return attrObj;
 }
function Sync(method, model, opts) {
    var table = model.config.adapter.collection_name,
        columns = model.config.columns,
        dbName = model.config.adapter.db_name || ALLOY_DB_DEFAULT,
        resp = null,
        db;
    model.idAttribute = model.config.adapter.idAttribute || "id";

	// Debug mode
    var DEBUG = model.config.debug;

    // last modified
    var lastModifiedColumn = model.config.adapter.lastModifiedColumn;
    var addModifedToUrl = model.config.adapter.addModifedToUrl;
    var lastModifiedDateFormat = model.config.adapter.lastModifiedDateFormat;
	
	// eTag enabled
	var eTagEnabled = model.config.eTagEnabled;
	
    // Used for custom parsing of the response data
    var parentNode = model.config.parentNode;

    // Validate the response data and only allow those items with all columns defined in the object to be saved to the database.
    var useStrictValidation = model.config.useStrictValidation;

    // before fethcing data from remote server - the adapter will return the stored data if enabled
    var initFetchWithLocalData = model.config.initFetchWithLocalData;

    // if enabled - it will delete all the rows in the table on a succesful fetch
    var deleteAllOnFetch = model.config.deleteAllOnFetch;

    // save data locally on server error?
    var disableSaveDataLocallyOnServerError = model.config.disableSaveDataLocallyOnServerError;

    // Are we dealing with a colleciton or a model?
    var isCollection = (model instanceof Backbone.Collection) ? true : false;

    // returns the error response instead of the local data
    var returnErrorResponse = model.config.returnErrorResponse;

    var singleModelRequest = null;
    if (lastModifiedColumn) {
        if (opts.sql && opts.sql.where) {
            singleModelRequest = opts.sql.where[model.idAttribute];
        }
        if (!singleModelRequest && opts.data && opts.data[model.idAttribute]) {
            singleModelRequest = opts.data[model.idAttribute];
        }
    }

    //REST API
    var methodMap = {
        'create': 'POST',
        'read': 'GET',
        'update': 'PUT',
        'delete': 'DELETE'
    };

    var type = methodMap[method];
    var params = _.extend({}, opts);
    params.type = type;

    //set default headers
    params.headers = params.headers || {};

    // Send our own custom headers
    if (model.config.hasOwnProperty("headers")) {
        for (header in model.config.headers) {
            params.headers[header] = model.config.headers[header];
        }
    }

    // We need to ensure that we have a base url.
    if (!params.url) {
        params.url = (model.config.URL || model.url());
        if (!params.url) {
            Ti.API.error("[SQL REST API] ERROR: NO BASE URL");
            return;
        }
    }
	
	// Check if Last Modified is active
    if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
        //send last modified model datestamp to the remote server
        var lastModifiedValue = "";
        try {
            lastModifiedValue = sqlLastModifiedItem();
        } catch (e) {
            logger(DEBUG, "LASTMOD SQL FAILED: ");

        }
        params.headers['Last-Modified'] = lastModifiedValue;
    }
    
    // Extend the provided url params with those from the model config
    if (_.isObject(params.urlparams) || model.config.URLPARAMS) {
        _.extend(params.urlparams, _.isFunction(model.config.URLPARAMS) ? model.config.URLPARAMS() : model.config.URLPARAMS);
    }

    // For older servers, emulate JSON by encoding the request into an HTML-form.
    if (Alloy.Backbone.emulateJSON) {
        params.contentType = 'application/x-www-form-urlencoded';
        params.processData = true;
        params.data = params.data ? {
            model: params.data
        } : {};
    }

    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
    // And an `X-HTTP-Method-Override` header.
    if (Alloy.Backbone.emulateHTTP) {
        if (type === 'PUT' || type === 'DELETE') {
            if (Alloy.Backbone.emulateJSON)
                params.data._method = type;
            params.type = 'POST';
            params.beforeSend = function(xhr) {
                params.headers['X-HTTP-Method-Override'] = type;
            };
        }
    }

    //json data transfers
    params.headers['Content-Type'] = 'application/json';

    logger(DEBUG, "REST METHOD: " + method);

    switch (method) {
        case 'create':
            // convert to string for API call
            params.data = JSON.stringify(model.toJSON());
            logger(DEBUG, "create options", params);

            apiCall(params, function(_response) {
                if (_response.success) {
                    var data = parseJSON(_response, parentNode);
                    // Rest API should return a new model id.
                    resp = saveData(data);
                    _.isFunction(params.success) && params.success(resp);
                } else {
                    // offline or error

                    // save data locally when server returned an error
                    if (!_response.localOnly && (params.disableSaveDataLocallyOnServerError || disableSaveDataLocallyOnServerError)) {
                        logger(DEBUG, "NOTICE: The data is not being saved locally");
                    } else {
                        resp = saveData();
                    }

                    if (_.isUndefined(_response.offline)) {
                        // error
                        _.isFunction(params.error) && params.error(returnErrorResponse ? _response : resp);
                    } else {
                        //offline - still a data success
                        _.isFunction(params.success) && params.success(resp);
                    }
                }
            });
            break;
        case 'read':

            if (!isCollection && model.id) {
                // find model by id
                params.url = params.url + '/' + model.id;
            }

            if (params.search) {
                // search mode
                params.returnExactServerResponse = true;
                params.url = params.url + "/search/" + Ti.Network.encodeURIComponent(params.search);
            }

            if (params.urlparams) {
                // build url with parameters
                params.url = encodeData(params.urlparams, params.url);
            }
            
            if(eTagEnabled){
            	params.eTagEnabled = true;
            }

            // check is all the necessary info is in place for last modified
            if (lastModifiedColumn && addModifedToUrl && lastModifiedValue) {
                // add last modified date to url
                var obj = {};
                obj[lastModifiedColumn] = lastModifiedValue;
                params.url = encodeData(obj, params.url);
            }

            logger(DEBUG, "read options", params);

            if (!params.localOnly && (params.initFetchWithLocalData || initFetchWithLocalData)) {
                // read local data before receiving server data
                resp = readSQL();
                _.isFunction(params.success) && params.success(resp);
                model.trigger("fetch", {
                    serverData: false
                });
            }

            apiCall(params, function(_response) {
                if (_response.success) {
                    if (deleteAllOnFetch || params.deleteAllOnFetch) {
                        deleteAllSQL();
                    }

                    var data = parseJSON(_response, parentNode);
                    if (!params.localOnly) {
                        //we dont want to manipulate the data on localOnly requests
                        saveData(data);
                    }
                    resp = readSQL(data);
                    _.isFunction(params.success) && params.success(resp);
                    model.trigger("fetch");
                } else {
                    //error or offline - read local data
                    if ( params.initFetchWithLocalData || initFetchWithLocalData ) {
                    }else{
                    	resp = readSQL();
                    }
                    if (_.isUndefined(_response.offline)) {
                        //error
                        _.isFunction(params.error) && params.error(returnErrorResponse ? _response : resp);
                    } else {
                        //offline - still a data success
                        _.isFunction(params.success) && params.success(resp);
                        model.trigger("fetch");
                    }
                }
            });

            break;

        case 'update':
            if (!model.id) {
                params.error(null, "MISSING MODEL ID");
                Ti.API.error("[SQL REST API] ERROR: MISSING MODEL ID");
                return;
            }

            // setup the url & data
            if (_.indexOf(params.url, "?") == -1) {
                params.url = params.url + '/' + model.id;
            } else {
                var str = params.url.split("?");
                params.url = str[0] + '/' + model.id + "?" + str[1];
            }

            if (params.urlparams) {
                params.url = encodeData(params.urlparams, params.url);
            }

            params.data = JSON.stringify(model.toJSON());
            logger(DEBUG, "update options", params);

            apiCall(params, function(_response) {
                if (_response.success) {
                    var data = parseJSON(_response, parentNode);
                    resp = saveData(data);
                    _.isFunction(params.success) && params.success(resp);
                } else {
                    // error or offline - save & use local data

                    // save data locally when server returned an error
                    if (!_response.localOnly && (params.disableSaveDataLocallyOnServerError || disableSaveDataLocallyOnServerError)) {
                        logger(DEBUG, "NOTICE: The data is not being saved locally");
                    } else {
                        resp = saveData();
                    }

                    if (_.isUndefined(_response.offline)) {
                        //error
                        _.isFunction(params.error) && params.error(returnErrorResponse ? _response : resp);
                    } else {
                        //offline - still a data success
                        _.isFunction(params.success) && params.success(resp);
                    }
                }
            });
            break;
        case 'delete':
            if (!model.id) {
                params.error(null, "MISSING MODEL ID");
                Ti.API.error("[SQL REST API] ERROR: MISSING MODEL ID");
                return;
            }
            params.url = params.url + '/' + model.id;
            logger(DEBUG, "delete options", params);

            apiCall(params, function(_response) {
                if (_response.success) {
                    var data = parseJSON(_response, parentNode);
                    resp = deleteSQL();
                    _.isFunction(params.success) && params.success(resp);
                } else {
                    // error or offline

                    // save data locally when server returned an error
                    if (!_response.localOnly && (params.disableSaveDataLocallyOnServerError || disableSaveDataLocallyOnServerError)) {
                        logger(DEBUG, "NOTICE: The data is not being deleted locally");
                    } else {
                        resp = deleteSQL();
                    }

                    if (_.isUndefined(_response.offline)) {
                        //error
                        _.isFunction(params.error) && params.error(returnErrorResponse ? _response : resp);
                    } else {
                        //offline - still a data success
                        _.isFunction(params.success) && params.success(resp);
                    }
                }
            });
            break;
    }

    /////////////////////////////////////////////
    //SQL INTERFACE
    /////////////////////////////////////////////
    function saveData(data) {
        if (!data && !isCollection) {
            data = model.toJSON();
        }
        if (!data) {
            // its empty
            return;
        }
        if (!_.isArray(data)) { // its a model
            if (!_.isUndefined(data["is_deleted"])) {
                //delete item
                deleteSQL(data[model.idAttribute]);
            } else if (sqlFindItem(data[model.idAttribute]).length == 1) {
                //item exists - update it
                return updateSQL(data);
            } else {
                //write data to local sql
                return createSQL(data);
            }
        } else { //its an array of models
            var currentModels = sqlCurrentModels();
            for (var i in data) {
                if (!_.isUndefined(data[i]["is_deleted"])) {
                    //delete item
                    deleteSQL(data[i][model.idAttribute]);
                } else if (_.indexOf(currentModels, data[i][model.idAttribute]) != -1) {
                    //item exists - update it
                    updateSQL(data[i]);
                } else {
                    //write data to local sql
                    createSQL(data[i]);
                }
            }
        }
    }

    function createSQL(data) {
        var attrObj = {};
        logger(DEBUG, "createSQL data:", data);

        if (data) {
            attrObj = data;
        } else {
            if (!isCollection) {
                attrObj = model.toJSON();
            } else {
                Ti.API.error("[SQL REST API] Its a collection - error !");
            }
        }

        if (!attrObj[model.idAttribute]) {
            if (model.idAttribute === ALLOY_ID_DEFAULT) {
                // alloy-created GUID field
                attrObj.id = guid();
                attrObj[model.idAttribute] = attrObj.id;
            } else {
                // idAttribute not assigned by alloy. Leave it empty and
                // allow sqlite to process as null, which is the
                // expected value for an AUTOINCREMENT field.
                attrObj[model.idAttribute] = null;
            }
        }

        //validate the item
        if (useStrictValidation) {
            for (var c in columns) {
                if (c == model.idAttribute) {
                    continue;
                }
                if (!_.contains(_.keys(attrObj), c)) {
                    Ti.API.error("[SQL REST API] ITEM NOT VALID - REASON: " + c + " is not present");
                    return;
                }
            }
        }

        // Create arrays for insert query
        var names = [],
            values = [],
            q = [];
        for (var k in columns) {
            names.push(k);
            if (_.isObject(attrObj[k])) {
                values.push(JSON.stringify(attrObj[k]));
            } else {
                values.push(attrObj[k]);
            }
            q.push('?');
        }

        // Last Modified logic
        if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
            values[_.indexOf(names, lastModifiedColumn)] = lastModifiedDateFormat ? moment().format(lastModifiedDateFormat) : moment().format('YYYY-MM-DD HH:mm:ss');
        }

        // Assemble create query
        var sqlInsert = "INSERT INTO " + table + " (" + names.join(",") + ") VALUES (" + q.join(",") + ");";

        // execute the query and return the response
        db = Ti.Database.open(dbName);
        db.execute('BEGIN;');
        db.execute(sqlInsert, values);

        // get the last inserted id
        if (model.id === null) {
            var sqlId = "SELECT last_insert_rowid();";
            var rs = db.execute(sqlId);
            if (rs.isValidRow()) {
                model.id = rs.field(0);
                attrObj[model.idAttribute] = model.id;
            } else {
                Ti.API.warn('Unable to get ID from database for model: ' + model.toJSON());
            }
        }

        db.execute('COMMIT;');
        db.close();

        return attrObj;
    }

    function readSQL(data) {
        if (DEBUG) {
            Ti.API.debug("[SQL REST API] readSQL");
            logger(DEBUG, "\n******************************\nCollection total BEFORE read from db: " + model.length + " models\n******************************");
        }
        var sql = opts.query || 'SELECT * FROM ' + table;

        // we want the exact server response returned by the adapter
        if (params.returnExactServerResponse && data) {
            opts.sql = opts.sql || {};
            opts.sql.where = opts.sql.where || {};

            if (_.isEmpty(data)) {
                // No result
                opts.sql.where[model.idAttribute] = "1=2";
            } else {
                // Find all idAttribute in the server response
                var ids = [];
                _.each(data, function(element) {
                    ids.push(element[model.idAttribute]);
                });
                // this will select IDs in the sql query
                opts.sql.where[model.idAttribute] = ids;
            }
        }

        // execute the select query
        db = Ti.Database.open(dbName);

        // run a specific sql query if defined
        if (opts.query) {
            if (opts.query.params) {
                var rs = db.execute(opts.query.sql, opts.query.params);
            } else {
                var rs = db.execute(opts.query.sql);
            }
        } else {
            //extend sql where with data
            if (opts.data) {
                opts.sql = opts.sql || {};
                opts.sql.where = opts.sql.where || {};
                _.extend(opts.sql.where, opts.data);
            }
            // build the sql query
            var sql = _buildQuery(table, opts.sql || opts);
            logger(DEBUG, "SQL QUERY: " + sql);

            var rs = db.execute(sql);
        }
        var len = 0,
            values = [];

        // iterate through all queried rows
        while (rs.isValidRow()) {
            var o = {};
            var fc = 0;

            fc = _.isFunction(rs.fieldCount) ? rs.fieldCount() : rs.fieldCount;

            // create list of rows returned from query
            _.times(fc, function(c) {
                var fn = rs.fieldName(c);
                o[fn] = rs.fieldByName(fn);
            });
            values.push(o);

            // Only push models if its a collection
            // and not if we are using fetch({add:true})
            if (isCollection && !params.add) {
                //push the models
                var m = new model.config.Model(o);
                model.models.push(m);
            }
            len++;
            rs.next();
        }

        // close off db after read query
        rs.close();
        db.close();

        // shape response based on whether it's a model or collection
        model.length = len;

        logger(DEBUG, "\n******************************\n readSQL db read complete: " + len + " models \n******************************");
        resp = len === 1 ? values[0] : values;
        return resp;
    }

    function updateSQL(data) {
        var attrObj = {};

        logger(DEBUG, "updateSQL data: ", data);

        if (data) {
            attrObj = data;
        } else {
            if (!isCollection) {
                attrObj = model.toJSON();
            } else {
                Ti.API.error("Its a collection - error!");
            }
        }

        // Create arrays for insert query
        var names = [],
            values = [],
            q = [];
        for (var k in columns) {
            if (!_.isUndefined(attrObj[k])) { //only update those who are in the data
                names.push(k + '=?');
                if (_.isObject(attrObj[k])) {
                    values.push(JSON.stringify(attrObj[k]));
                } else {
                    values.push(attrObj[k]);
                }
                q.push('?');
            }
        }

        if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
            values[_.indexOf(names, lastModifiedColumn + "=?")] = lastModifiedDateFormat ? moment().format(lastModifiedDateFormat) : moment().format('YYYY-MM-DD HH:mm:ss');
        }

        // compose the update query
        var sql = 'UPDATE ' + table + ' SET ' + names.join(',') + ' WHERE ' + model.idAttribute + '=?';
        values.push(attrObj[model.idAttribute]);

        logger(DEBUG, "updateSQL sql query: " + sql);
        logger(DEBUG, "updateSQL values: ", values);

        // execute the update
        db = Ti.Database.open(dbName);
        db.execute(sql, values);

        db.close();

        return attrObj;
    }

    function deleteSQL(id) {
        var sql = 'DELETE FROM ' + table + ' WHERE ' + model.idAttribute + '=?';
        // execute the delete
        db = Ti.Database.open(dbName);
        db.execute(sql, id || model.id);
        db.close();

        model.id = null;
        return model.toJSON();
    }

    function deleteAllSQL() {
        var sql = 'DELETE FROM ' + table;
        db = Ti.Database.open(dbName);
        db.execute(sql);
        db.close();
    }

    function sqlCurrentModels() {
        var sql = 'SELECT ' + model.idAttribute + ' FROM ' + table;
        db = Ti.Database.open(dbName);
        var rs = db.execute(sql);
        var output = [];
        while (rs.isValidRow()) {
            output.push(rs.fieldByName(model.idAttribute));
            rs.next();
        }
        rs.close();
        db.close();
        return output;
    }

    function sqlFindItem(_id) {
        if (_.isUndefined(_id)) {
            return [];
        }
        var sql = 'SELECT ' + model.idAttribute + ' FROM ' + table + ' WHERE ' + model.idAttribute + '=?';
        db = Ti.Database.open(dbName);
        var rs = db.execute(sql, _id);
        var output = [];
        while (rs.isValidRow()) {
            output.push(rs.fieldByName(model.idAttribute));
            rs.next();
        }
        rs.close();
        db.close();
        return output;
    }

    function sqlLastModifiedItem() {
        if (singleModelRequest || !isCollection) {
            //model
            var sql = 'SELECT ' + lastModifiedColumn + ' FROM ' + table + ' WHERE ' + lastModifiedColumn + ' IS NOT NULL AND ' + model.idAttribute + '=' + singleModelRequest + ' ORDER BY ' + lastModifiedColumn + ' DESC LIMIT 0,1';
        } else {
            //collection
            var sql = 'SELECT ' + lastModifiedColumn + ' FROM ' + table + ' WHERE ' + lastModifiedColumn + ' IS NOT NULL ORDER BY ' + lastModifiedColumn + ' DESC LIMIT 0,1';
        }

        db = Ti.Database.open(dbName);
        rs = db.execute(sql);
        var output = null;
        if (rs.isValidRow()) {
            output = rs.field(0);
        }
        rs.close();
        db.close();
        return output;
    }

    function parseJSON(_response, parentNode) {
        var data = _response.responseJSON;
        if (!_.isUndefined(parentNode)) {
            data = _.isFunction(parentNode) ? parentNode(data) : traverseProperties(data, parentNode);
        }
        logger(DEBUG, "server response: ", data);
        return data;
    }

}
Example #16
0
exports.createStyle = function(controller, opts, defaults) {
	var classes, apiName;

	// If there's no opts, there's no reason to load the style module. Just
	// return an empty object.
	if (!opts) { return {}; }

	// make opts.classes an array if it isn't already
	if (_.isArray(opts.classes)) {
		classes = opts.classes.slice(0);
	} else if (_.isString(opts.classes)) {
		classes = opts.classes.split(/\s+/);
	} else {
		classes = [];
	}

	// give opts.apiName a namespace if it doesn't have one already
	apiName = opts.apiName;
	if (apiName && apiName.indexOf('.') === -1) {
		apiName = addNamespace(apiName);
	}

	// TODO: check cached styles based on opts and controller

	// Load the runtime style for the given controller
	var styleArray;
	if (controller && _.isObject(controller)) {
		styleArray = require('alloy/widgets/' + controller.widgetId +
			'/styles/' + controller.name);
	} else {
		styleArray = require('alloy/styles/' + controller);
	}
	var styleFinal = {};

	// iterate through all styles
	var i, len;
	for (i = 0, len = styleArray.length; i < len; i++) {
		var style = styleArray[i];

		// give the apiName a namespace if necessary
		var styleApi = style.key;
		if (style.isApi && styleApi.indexOf('.') === -1) {
			styleApi = (CONST.IMPLICIT_NAMESPACES[styleApi] ||
				CONST.NAMESPACE_DEFAULT) + '.' + styleApi;
		}

		// does this style match the given opts?
		if ((style.isId && opts.id && style.key === opts.id) ||
			(style.isClass && _.contains(classes, style.key))) {
			// do nothing here, keep on processing
		} else if (style.isApi) {
			if (style.key.indexOf('.') === -1) {
				style.key = addNamespace(style.key);
			}
			if (style.key !== apiName) { continue; }
		} else {
			// no matches, skip this style
			continue;
		}

		// can we clear out any form factor queries?
		if (style.queries && style.queries.formFactor &&
			!Alloy[style.queries.formFactor]) {
			continue;
		}

		// Merge this style into the existing style object
		deepExtend(true, styleFinal, style.style);
	}

	// TODO: cache the style based on the opts and controller

	// Merge remaining extra style properties from opts, if any
	var extraStyle = _.omit(opts, [
		CONST.CLASS_PROPERTY,
		CONST.APINAME_PROPERTY
	]);
	deepExtend(true, styleFinal, extraStyle);
	styleFinal[CONST.CLASS_PROPERTY] = classes;
	styleFinal[CONST.APINAME_PROPERTY] = apiName;

	if (MW320_CHECK) { delete styleFinal[CONST.APINAME_PROPERTY]; }

	return defaults ? _.defaults(styleFinal,defaults) : styleFinal;
};
Example #17
0
	return JSON.stringify(obj, function(k, v) {
		if (_.isObject(v) && !_.isArray(v) && !_.isFunction(v)) {
			return sortObject(v);
		}
		return v;
	});
Example #18
0
function ucfirst(e){return e?e[0].toUpperCase()+e.substr(1):e}function addNamespace(e){return(CONST.IMPLICIT_NAMESPACES[e]||CONST.NAMESPACE_DEFAULT)+"."+e}function processStyle(e,t,o,r,n){r=r||{},r.classes=o,t.apiName&&(r.apiName=t.apiName),t.id&&(r.id=t.id),t.applyProperties(exports.createStyle(e,r,n))}function isTabletFallback(){return Math.min(Ti.Platform.displayCaps.platformHeight,Ti.Platform.displayCaps.platformWidth)>=700}var _=require("alloy/underscore")._,Backbone=require("alloy/backbone"),CONST=require("alloy/constants");exports.version="1.3.0",exports._=_,exports.Backbone=Backbone;var DEFAULT_WIDGET="widget",TI_VERSION=Ti.version,MW320_CHECK=!0&&TI_VERSION>="3.2.0",IDENTITY_TRANSFORM=void 0,RESET={bottom:null,left:null,right:null,top:null,height:null,width:null,shadowColor:null,shadowOffset:null,backgroundImage:null,backgroundRepeat:null,center:null,layout:null,backgroundSelectedColor:null,backgroundSelectedImage:null,opacity:1,touchEnabled:!0,enabled:!0,horizontalWrap:!0,zIndex:0,backgroundColor:null,font:null,visible:!0,color:null,transform:null,backgroundGradient:{},borderColor:"transparent",borderRadius:null,borderWidth:null};exports.M=function(e,t,o){var r,n=(t||{}).config||{},s=n.adapter||{},l={},a={};s.type?(r=require("alloy/sync/"+s.type),l.sync=function(e,t,o){r.sync(e,t,o)}):l.sync=function(e,t){Ti.API.warn("Execution of "+e+"#sync() function on a model that does not support persistence"),Ti.API.warn("model: "+JSON.stringify(t.toJSON()))},l.defaults=n.defaults,o&&(a.migrations=o),r&&_.isFunction(r.beforeModelCreate)&&(n=r.beforeModelCreate(n,e)||n);var i=Backbone.Model.extend(l,a);return i.prototype.config=n,_.isFunction(t.extendModel)&&(i=t.extendModel(i)||i),r&&_.isFunction(r.afterModelCreate)&&r.afterModelCreate(i,e),i},exports.C=function(e,t,o){var r,n={model:o},s=(o?o.prototype.config:{})||{};s.adapter&&s.adapter.type?(r=require("alloy/sync/"+s.adapter.type),n.sync=function(e,t,o){r.sync(e,t,o)}):n.sync=function(e,t){Ti.API.warn("Execution of "+e+"#sync() function on a collection that does not support persistence"),Ti.API.warn("model: "+JSON.stringify(t.toJSON()))};var l=Backbone.Collection.extend(n);return l.prototype.config=s,_.isFunction(t.extendCollection)&&(l=t.extendCollection(l)||l),r&&_.isFunction(r.afterCollectionCreate)&&r.afterCollectionCreate(l),l},exports.UI={},exports.UI.create=function(controller,apiName,opts){opts=opts||{};var baseName,ns,parts=apiName.split(".");if(1===parts.length)baseName=apiName,ns=opts.ns||CONST.IMPLICIT_NAMESPACES[baseName]||CONST.NAMESPACE_DEFAULT;else{if(!(parts.length>1))throw"Alloy.UI.create() failed: No API name was given in the second parameter";baseName=parts[parts.length-1],ns=parts.slice(0,parts.length-1).join(".")}opts.apiName=ns+"."+baseName,baseName=baseName[0].toUpperCase()+baseName.substr(1);var style=exports.createStyle(controller,opts);return eval(ns)["create"+baseName](style)},exports.createStyle=function(e,t,o){var r,n;if(!t)return{};r=_.isArray(t.classes)?t.classes.slice(0):_.isString(t.classes)?t.classes.split(/\s+/):[],n=t.apiName,n&&-1===n.indexOf(".")&&(n=addNamespace(n));var s;s=require(e&&_.isObject(e)?"alloy/widgets/"+e.widgetId+"/styles/"+e.name:"alloy/styles/"+e);var l,a,i={};for(l=0,a=s.length;a>l;l++){var p=s[l],c=p.key;if(p.isApi&&-1===c.indexOf(".")&&(c=(CONST.IMPLICIT_NAMESPACES[c]||CONST.NAMESPACE_DEFAULT)+"."+c),p.isId&&t.id&&p.key===t.id||p.isClass&&_.contains(r,p.key));else{if(!p.isApi)continue;if(-1===p.key.indexOf(".")&&(p.key=addNamespace(p.key)),p.key!==n)continue}p.queries&&p.queries.formFactor&&!Alloy[p.queries.formFactor]||_.extend(i,p.style)}var u=_.omit(t,[CONST.CLASS_PROPERTY,CONST.APINAME_PROPERTY]);return _.extend(i,u),i[CONST.CLASS_PROPERTY]=r,i[CONST.APINAME_PROPERTY]=n,MW320_CHECK&&delete i[CONST.APINAME_PROPERTY],o?_.defaults(i,o):i},exports.addClass=function(e,t,o,r){if(!o)return void(r&&(MW320_CHECK&&delete r.apiName,t.applyProperties(r)));var n=t[CONST.CLASS_PROPERTY]||[],s=n.length;o=_.isString(o)?o.split(/\s+/):o;var l=_.union(n,o||[]);return s===l.length?void(r&&(MW320_CHECK&&delete r.apiName,t.applyProperties(r))):void processStyle(e,t,l,r)},exports.removeClass=function(e,t,o,r){o=o||[];var n=t[CONST.CLASS_PROPERTY]||[],s=n.length;if(!s||!o.length)return void(r&&(MW320_CHECK&&delete r.apiName,t.applyProperties(r)));o=_.isString(o)?o.split(/\s+/):o;var l=_.difference(n,o);return s===l.length?void(r&&(MW320_CHECK&&delete r.apiName,t.applyProperties(r))):void processStyle(e,t,l,r,RESET)},exports.resetClass=function(e,t,o,r){o=o||[],o=_.isString(o)?o.split(/\s+/):o,processStyle(e,t,o,r,RESET)},exports.createWidget=function(e,t,o){return"undefined"!=typeof t&&null!==t&&_.isObject(t)&&!_.isString(t)&&(o=t,t=DEFAULT_WIDGET),new(require("alloy/widgets/"+e+"/controllers/"+(t||DEFAULT_WIDGET)))(o)},exports.createController=function(e,t){return new(require("alloy/controllers/"+e))(t)},exports.createModel=function(e,t){return new(require("alloy/models/"+ucfirst(e)).Model)(t)},exports.createCollection=function(e,t){return new(require("alloy/models/"+ucfirst(e)).Collection)(t)},exports.isTablet=function(){return Math.min(Ti.Platform.displayCaps.platformHeight,Ti.Platform.displayCaps.platformWidth)>=400}(),exports.isHandheld=!exports.isTablet,exports.Globals={},exports.Models={},exports.Models.instance=function(e){return exports.Models[e]||(exports.Models[e]=exports.createModel(e))},exports.Collections={},exports.Collections.instance=function(e){return exports.Collections[e]||(exports.Collections[e]=exports.createCollection(e))},exports.CFG=require("alloy/CFG");
function Sync(method, model, opts) {
    model.idAttribute = model.config.adapter.idAttribute || "id";
    var DEBUG = model.config.debug;
    var eTagEnabled = model.config.eTagEnabled;
    var parentNode = model.config.parentNode;
    var methodMap = {
        create: "POST",
        read: "GET",
        update: "PUT",
        "delete": "DELETE"
    };
    var type = methodMap[method];
    var params = _.extend({}, opts);
    params.type = type;
    params.headers = params.headers || {};
    if (model.config.hasOwnProperty("headers")) for (var header in model.config.headers) params.headers[header] = model.config.headers[header];
    if (!params.url) {
        params.url = model.config.URL || model.url();
        if (!params.url) {
            Ti.API.error("[REST API] ERROR: NO BASE URL");
            return;
        }
    }
    if (_.isObject(params.urlparams) || model.config.URLPARAMS) {
        params.urlparams = params.urlparams || {};
        _.extend(params.urlparams, _.isFunction(model.config.URLPARAMS) ? model.config.URLPARAMS() : model.config.URLPARAMS);
    }
    if (Alloy.Backbone.emulateJSON) {
        params.contentType = "application/x-www-form-urlencoded";
        params.processData = true;
        params.data = params.data ? {
            model: params.data
        } : {};
    }
    if (Alloy.Backbone.emulateHTTP && ("PUT" === type || "DELETE" === type)) {
        Alloy.Backbone.emulateJSON && (params.data._method = type);
        params.type = "POST";
        params.beforeSend = function() {
            params.headers["X-HTTP-Method-Override"] = type;
        };
    }
    params.data || !model || "create" != method && "update" != method || (params.headers["Content-Type"] = "application/json");
    logger(DEBUG, "REST METHOD", method);
    switch (method) {
      case "create":
        params.data = JSON.stringify(model.toJSON());
        logger(DEBUG, "create options", params);
        apiCall(params, function(_response) {
            _response.success || (_response = fixResponseJSON(_response));
            if (_response.success) {
                var data = parseJSON(DEBUG, _response, parentNode, model);
                void 0 === data[model.idAttribute] && (data[model.idAttribute] = guid());
                params.success(data, JSON.stringify(data));
                model.trigger("fetch");
            } else {
                params.error(_response.responseJSON, _response.responseText);
                Ti.API.error("[REST API] CREATE ERROR: ");
                Ti.API.error(_response);
            }
        });
        break;

      case "read":
        model.id && (params.url = params.url + "/" + model.id);
        params.search && (params.url = params.url + "/search/" + Ti.Network.encodeURIComponent(params.search));
        params.urlparams && (params.url = encodeData(params.urlparams, params.url));
        !params.urlparams && params.data && (params.url = encodeData(params.data, params.url));
        eTagEnabled && (params.eTagEnabled = true);
        logger(DEBUG, "read options", params);
        apiCall(params, function(_response) {
            if (_response.success) {
                var data = parseJSON(DEBUG, _response, parentNode, model);
                var values = [];
                _.isArray(data) || (data = [ data ]);
                var length = 0;
                for (var i in data) {
                    var item = {};
                    item = data[i];
                    void 0 === item[model.idAttribute] && (item[model.idAttribute] = guid());
                    values.push(item);
                    length++;
                }
                params.success(1 === length ? values[0] : values, _response.responseText);
                model.trigger("fetch");
            } else {
                params.error(model, _response.responseText);
                Ti.API.error("[REST API] READ ERROR: ");
                Ti.API.error(_response);
            }
        });
        break;

      case "update":
        if (!model.id) {
            params.error(null, "MISSING MODEL ID");
            Ti.API.error("[REST API] ERROR: MISSING MODEL ID");
            return;
        }
        if (-1 == _.indexOf(params.url, "?")) params.url = params.url + "/" + model.id; else {
            var str = params.url.split("?");
            params.url = str[0] + "/" + model.id + "?" + str[1];
        }
        params.urlparams && (params.url = encodeData(params.urlparams, params.url));
        var nodeType = model.get("type") ? model.get("type") : "";
        if (nodeType.length > 0) var data = {
            type: nodeType
        }; else var data = {};
        for (changeAtt in params.changes) {
            Ti.API.info("changeAtt: " + changeAtt);
            data[changeAtt] = model.get(changeAtt);
        }
        params.data = JSON.stringify(data);
        logger(DEBUG, "update options", params);
        apiCall(params, function(_response) {
            if (_response.success) {
                var data = parseJSON(DEBUG, _response, parentNode, model);
                params.success(data, JSON.stringify(data));
                model.trigger("fetch");
            } else {
                params.error(model, _response.responseText);
                Ti.API.error("[REST API] UPDATE ERROR: ");
                Ti.API.error(_response);
            }
        });
        break;

      case "delete":
        if (!model.id) {
            params.error(null, "MISSING MODEL ID");
            Ti.API.error("[REST API] ERROR: MISSING MODEL ID");
            return;
        }
        if (-1 == _.indexOf(params.url, "?")) params.url = params.url + "/" + model.id; else {
            var str = params.url.split("?");
            params.url = str[0] + "/" + model.id + "?" + str[1];
        }
        logger(DEBUG, "delete options", params);
        apiCall(params, function(_response) {
            if (_response.success) {
                parseJSON(DEBUG, _response, parentNode, model);
                params.success(null, _response.responseText);
                model.trigger("fetch");
            } else {
                params.error(model, _response.responseText);
                Ti.API.error("[REST API] DELETE ERROR: ");
                Ti.API.error(_response);
            }
        });
    }
}
Example #20
0
	function createSQL(data) {
		var attrObj = {};

		if (DEBUG) {
			Ti.API.debug("[SQL REST API] createSQL data:");
			Ti.API.debug(data);
		}

		if (data) {
			attrObj = data;
		} else {
			if (!isCollection) {
				attrObj = model.toJSON();
			} else {
				Ti.API.error("[SQL REST API] Its a collection - error !");
			}
		}

		if (!attrObj[model.idAttribute]) {
			if (model.idAttribute === ALLOY_ID_DEFAULT) {
				// alloy-created GUID field
				attrObj.id = util.guid();
				attrObj[model.idAttribute] = attrObj.id;
			} else {
				// idAttribute not assigned by alloy. Leave it empty and
				// allow sqlite to process as null, which is the
				// expected value for an AUTOINCREMENT field.
				attrObj[model.idAttribute] = null;
			}
		}

		//validate the item
		if (useStrictValidation) {
			for (var c in columns) {
				if (c == model.idAttribute) {
					continue;
				}
				if (!_.contains(_.keys(attrObj), c)) {
					Ti.API.error("[SQL REST API] ITEM NOT VALID - REASON: " + c + " is not present");
					return;
				}
			}
		}

		// Create arrays for insert query
		var names = [], values = [], q = [];
		for (var k in columns) {
			names.push(k);
			if (_.isObject(attrObj[k])) {
				values.push(JSON.stringify(attrObj[k]));
			} else {
				values.push(attrObj[k]);
			}
			q.push('?');
		}
		// Last Modified logic
		// 
		if (lastModifiedColumn && _.isUndefined(params.disableLastModified)) {
			values[_.indexOf(names, lastModifiedColumn)] = lastModifiedDateFormat ? moment().format(lastModifiedDateFormat) : moment().format('YYYY-MM-DD HH:mm:ss');
		}

		// Assemble create query
		var sqlInsert = "INSERT INTO " + table + " (" + names.join(",") + ") VALUES (" + q.join(",") + ");";

		// execute the query and return the response
		db = Ti.Database.open(dbName);
		db.execute('BEGIN;');
		db.execute(sqlInsert, values);

		// get the last inserted id
		if (model.id === null) {
			var sqlId = "SELECT last_insert_rowid();";
			var rs = db.execute(sqlId);
			if (rs.isValidRow()) {
				model.id = rs.field(0);
				attrObj[model.idAttribute] = model.id;
			} else {
				Ti.API.warn('Unable to get ID from database for model: ' + model.toJSON());
			}
		}

		db.execute('COMMIT;');
		db.close();

		return attrObj;
	}
Example #21
0
function ucfirst(e){return e?e[0].toUpperCase()+e.substr(1):e}function addNamespace(e){return(CONST.IMPLICIT_NAMESPACES[e]||CONST.NAMESPACE_DEFAULT)+"."+e}function processStyle(e,t,i,n,r){n=n||{},n.classes=i,t.apiName&&(n.apiName=t.apiName),t.id&&(n.id=t.id),t.applyProperties(exports.createStyle(e,n,r)),t.classes=i}function isTabletFallback(){return Math.min(Ti.Platform.displayCaps.platformHeight,Ti.Platform.displayCaps.platformWidth)>=700}function deepExtend(){var e,t,i,n,r,o,a=arguments[0]||{},s=1,l=arguments.length,u=!1;for("boolean"==typeof a&&(u=a,a=arguments[1]||{},s=2),"object"==typeof a||_.isFunction(a)||(a={});l>s;s++)if(e=arguments[s],null!=e){"string"==typeof e&&(e=e.split(""));for(t in e)i=a[t],n=e[t],a!==n&&(u&&n&&(_.isObject(n)&&!_.has(n,"apiName")||(r=_.isArray(n)))&&!n.colors?(r?(r=!1,o=i&&_.isArray(i)?i:[]):o=_.isDate(n)?new Date(n.valueOf()):i&&_.isObject(i)?i:{},a[t]=deepExtend(u,o,n)):"undefined"!=typeof n?a[t]=n:n.colors&&(a[t]=n))}return a}var _=require("alloy/underscore")._,Backbone=require("alloy/backbone"),CONST=require("alloy/constants");exports.version="1.5.1",exports._=_,exports.Backbone=Backbone;var DEFAULT_WIDGET="widget",TI_VERSION=Ti.version,MW320_CHECK=!1,IDENTITY_TRANSFORM=Ti.UI.create2DMatrix(),RESET={bottom:null,left:null,right:null,top:null,height:null,width:null,shadowColor:null,shadowOffset:null,backgroundImage:null,backgroundRepeat:null,center:null,layout:null,backgroundSelectedColor:null,backgroundSelectedImage:null,opacity:1,touchEnabled:!0,enabled:!0,horizontalWrap:!0,zIndex:0,backgroundColor:"transparent",font:null,visible:!0,color:"#000",transform:IDENTITY_TRANSFORM,backgroundGradient:null,borderColor:null,borderRadius:null,borderWidth:null};RESET=_.extend(RESET,{backgroundDisabledColor:null,backgroundDisabledImage:null,backgroundFocusedColor:null,backgroundFocusedImage:null,focusable:!1,keepScreenOn:!1}),exports.M=function(e,t,i){var n,r=(t||{}).config||{},o=r.adapter||{},a={},s={};o.type?(n=require("alloy/sync/"+o.type),a.sync=function(e,t,i){n.sync(e,t,i)}):a.sync=function(e,t){Ti.API.warn("Execution of "+e+"#sync() function on a model that does not support persistence"),Ti.API.warn("model: "+JSON.stringify(t.toJSON()))},a.defaults=r.defaults,i&&(s.migrations=i),n&&_.isFunction(n.beforeModelCreate)&&(r=n.beforeModelCreate(r,e)||r);var l=Backbone.Model.extend(a,s);return l.prototype.config=r,_.isFunction(t.extendModel)&&(l=t.extendModel(l)||l),n&&_.isFunction(n.afterModelCreate)&&n.afterModelCreate(l,e),l},exports.C=function(e,t,i){var n,r={model:i},o=(i?i.prototype.config:{})||{};o.adapter&&o.adapter.type?(n=require("alloy/sync/"+o.adapter.type),r.sync=function(e,t,i){n.sync(e,t,i)}):r.sync=function(e,t){Ti.API.warn("Execution of "+e+"#sync() function on a collection that does not support persistence"),Ti.API.warn("model: "+JSON.stringify(t.toJSON()))};var a=Backbone.Collection.extend(r);return a.prototype.config=o,_.isFunction(t.extendCollection)&&(a=t.extendCollection(a)||a),n&&_.isFunction(n.afterCollectionCreate)&&n.afterCollectionCreate(a),a},exports.UI={},exports.UI.create=function(controller,apiName,opts){opts=opts||{};var baseName,ns,parts=apiName.split(".");if(1===parts.length)baseName=apiName,ns=opts.ns||CONST.IMPLICIT_NAMESPACES[baseName]||CONST.NAMESPACE_DEFAULT;else{if(!(parts.length>1))throw"Alloy.UI.create() failed: No API name was given in the second parameter";baseName=parts[parts.length-1],ns=parts.slice(0,parts.length-1).join(".")}opts.apiName=ns+"."+baseName,baseName=baseName[0].toUpperCase()+baseName.substr(1);var style=exports.createStyle(controller,opts);return eval(ns)["create"+baseName](style)},exports.createStyle=function(e,t,i){var n,r;if(!t)return{};n=_.isArray(t.classes)?t.classes.slice(0):_.isString(t.classes)?t.classes.split(/\s+/):[],r=t.apiName,r&&-1===r.indexOf(".")&&(r=addNamespace(r));var o;o=require(e&&_.isObject(e)?"alloy/widgets/"+e.widgetId+"/styles/"+e.name:"alloy/styles/"+e);var a,s,l={};for(a=0,s=o.length;s>a;a++){var u=o[a],c=u.key;if(u.isApi&&-1===c.indexOf(".")&&(c=(CONST.IMPLICIT_NAMESPACES[c]||CONST.NAMESPACE_DEFAULT)+"."+c),u.isId&&t.id&&u.key===t.id||u.isClass&&_.contains(n,u.key));else{if(!u.isApi)continue;if(-1===u.key.indexOf(".")&&(u.key=addNamespace(u.key)),u.key!==r)continue}u.queries&&u.queries.formFactor&&!Alloy[u.queries.formFactor]||deepExtend(!0,l,u.style)}var d=_.omit(t,[CONST.CLASS_PROPERTY,CONST.APINAME_PROPERTY]);return deepExtend(!0,l,d),l[CONST.CLASS_PROPERTY]=n,l[CONST.APINAME_PROPERTY]=r,MW320_CHECK&&delete l[CONST.APINAME_PROPERTY],i?_.defaults(l,i):l},exports.addClass=function(e,t,i,n){if(!i)return void(n&&(MW320_CHECK&&delete n.apiName,t.applyProperties(n)));var r=t[CONST.CLASS_PROPERTY]||[],o=r.length;i=_.isString(i)?i.split(/\s+/):i;var a=_.union(r,i||[]);return o===a.length?void(n&&(MW320_CHECK&&delete n.apiName,t.applyProperties(n))):void processStyle(e,t,a,n)},exports.removeClass=function(e,t,i,n){i=i||[];var r=t[CONST.CLASS_PROPERTY]||[],o=r.length;if(!o||!i.length)return void(n&&(MW320_CHECK&&delete n.apiName,t.applyProperties(n)));i=_.isString(i)?i.split(/\s+/):i;var a=_.difference(r,i);return o===a.length?void(n&&(MW320_CHECK&&delete n.apiName,t.applyProperties(n))):void processStyle(e,t,a,n,RESET)},exports.resetClass=function(e,t,i,n){i=i||[],i=_.isString(i)?i.split(/\s+/):i,processStyle(e,t,i,n,RESET)},exports.createWidget=function(e,t,i){return"undefined"!=typeof t&&null!==t&&_.isObject(t)&&!_.isString(t)&&(i=t,t=DEFAULT_WIDGET),new(require("alloy/widgets/"+e+"/controllers/"+(t||DEFAULT_WIDGET)))(i)},exports.createController=function(e,t){return new(require("alloy/controllers/"+e))(t)},exports.createModel=function(e,t){return new(require("alloy/models/"+ucfirst(e)).Model)(t)},exports.createCollection=function(e,t){return new(require("alloy/models/"+ucfirst(e)).Collection)(t)},exports.isTablet=function(){var e=Ti.Platform.Android.physicalSizeCategory;return e===Ti.Platform.Android.PHYSICAL_SIZE_CATEGORY_LARGE||e===Ti.Platform.Android.PHYSICAL_SIZE_CATEGORY_XLARGE}(),exports.isHandheld=!exports.isTablet,exports.Globals={},exports.Models={},exports.Models.instance=function(e){return exports.Models[e]||(exports.Models[e]=exports.createModel(e))},exports.Collections={},exports.Collections.instance=function(e){return exports.Collections[e]||(exports.Collections[e]=exports.createCollection(e))},exports.CFG=require("alloy/CFG"),exports.Android={},exports.Android.menuItemCreateArgs=["itemId","groupId","title","order","actionView","checkable","checked","enabled","icon","showAsAction","titleCondensed","visible"];
function Sync(method, model, opts) {
	model.idAttribute = model.config.adapter.idAttribute || "id";

	// Debug mode
	var DEBUG = model.config.debug;

	// eTag enabled
	var eTagEnabled = model.config.eTagEnabled;

	// Used for custom parsing of the response data
	var parentNode = model.config.parentNode;

	// REST - CRUD
	var methodMap = {
		'create' : 'POST',
		'read' : 'GET',
		'update' : 'PUT',
		'delete' : 'DELETE'
	};

	var type = methodMap[method];
	var params = _.extend({}, opts);
	params.type = type;

	//set default headers
	params.headers = params.headers || {};

	// Send our own custom headers
	if (model.config.hasOwnProperty("headers")) {
		for (var header in model.config.headers) {
			params.headers[header] = model.config.headers[header];
		}
	}

	// We need to ensure that we have a base url.
	if (!params.url) {
		params.url = (model.config.URL || model.url());
		if (!params.url) {
			Ti.API.error("[REST API] ERROR: NO BASE URL");
			return;
		}
	}

	// Extend the provided url params with those from the model config
	if (_.isObject(params.urlparams) || model.config.URLPARAMS) {
		_.extend(params.urlparams, _.isFunction(model.config.URLPARAMS) ? model.config.URLPARAMS() : model.config.URLPARAMS);
	}

	// For older servers, emulate JSON by encoding the request into an HTML-form.
	if (Alloy.Backbone.emulateJSON) {
		params.contentType = 'application/x-www-form-urlencoded';
		params.processData = true;
		params.data = params.data ? {
			model : params.data
		} : {};
	}

	// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
	// And an `X-HTTP-Method-Override` header.
	if (Alloy.Backbone.emulateHTTP) {
		if (type === 'PUT' || type === 'DELETE') {
			if (Alloy.Backbone.emulateJSON)
				params.data._method = type;
			params.type = 'POST';
			params.beforeSend = function(xhr) {
				params.headers['X-HTTP-Method-Override'] = type;
			};
		}
	}

	//json data transfers
	params.headers['Content-Type'] = 'application/json';

	logger(DEBUG, "REST METHOD", method);

	switch(method) {
		case 'create' :
			// convert to string for API call
			params.data = JSON.stringify(model.toJSON());
			logger(DEBUG, "create options", params);

			apiCall(params, function(_response) {
				if (_response.success) {
					var data = parseJSON(DEBUG, _response, parentNode);

					//Rest API should return a new model id.
					if (data[model.idAttribute] === undefined) {
						//if not - create one
						data[model.idAttribute] = guid();
					}
					params.success(data, JSON.stringify(data));
					model.trigger("fetch");
					// fire event
				} else {
					params.error(_response.responseJSON, _response.responseText);
					Ti.API.error('[REST API] CREATE ERROR: ');
					Ti.API.error(_response);
				}
			});
			break;

		case 'read':
			if (model[model.idAttribute]) {
				params.url = params.url + '/' + model[model.idAttribute];
			}

			if (params.search) {
				// search mode
				params.url = params.url + "/search/" + Ti.Network.encodeURIComponent(params.search);
			}

			if (params.urlparams) {
				// build url with parameters
				params.url = encodeData(params.urlparams, params.url);
			}

			if (eTagEnabled) {
				params.eTagEnabled = true;
			}

			logger(DEBUG, "read options", params);

			apiCall(params, function(_response) {
				if (_response.success) {
					var data = parseJSON(DEBUG, _response, parentNode);
					var values = [];
					model.length = 0;
					for (var i in data) {
						var item = {};
						item = data[i];
						if (item[model.idAttribute] === undefined) {
							item[model.idAttribute] = guid();
						}
						values.push(item);
						model.length++;
					}

					params.success((model.length === 1) ? values[0] : values, _response.responseText);
					model.trigger("fetch");
				} else {
					params.error(model, _response.responseText);
					Ti.API.error('[REST API] READ ERROR: ');
					Ti.API.error(_response);
				}
			});
			break;

		case 'update' :
			if (!model[model.idAttribute]) {
				params.error(null, "MISSING MODEL ID");
				Ti.API.error("[REST API] ERROR: MISSING MODEL ID");
				return;
			}

			// setup the url & data
			if (_.indexOf(params.url, "?") == -1) {
				params.url = params.url + '/' + model[model.idAttribute];
			} else {
				var str = params.url.split("?");
				params.url = str[0] + '/' + model[model.idAttribute] + "?" + str[1];
			}

			if (params.urlparams) {
				params.url = encodeData(params.urlparams, params.url);
			}

			params.data = JSON.stringify(model.toJSON());

			logger(DEBUG, "update options", params);

			apiCall(params, function(_response) {
				if (_response.success) {
					var data = parseJSON(DEBUG, _response, parentNode);
					params.success(data, JSON.stringify(data));
					model.trigger("fetch");
				} else {
					params.error(model, _response.responseText);
					Ti.API.error('[REST API] UPDATE ERROR: ');
					Ti.API.error(_response);
				}
			});
			break;

		case 'delete' :
			if (!model[model.idAttribute]) {
				params.error(null, "MISSING MODEL ID");
				Ti.API.error("[REST API] ERROR: MISSING MODEL ID");
				return;
			}
			params.url = params.url + '/' + model[model.idAttribute];

			logger(DEBUG, "delete options", params);

			apiCall(params, function(_response) {
				if (_response.success) {
					var data = parseJSON(DEBUG, _response, parentNode);
					params.success(null, _response.responseText);
					model.trigger("fetch");
				} else {
					params.error(model, _response.responseText);
					Ti.API.error('[REST API] DELETE ERROR: ');
					Ti.API.error(_response);
				}
			});
			break;
	}

}