/**
* @namespace LiveView
*/
;(function(window, $, undefined){
'use strict';
var tmpPrototype;
/** @alias LiveView.prototype */
window.LiveView = {
Table: Table,
Query: Query,
Schema: Schema,
Field: Field,
Tuple: Tuple,
Error: Error,
_internal: {}
};
/**
* Defines the properties of a LiveView Table. Properties are read-only.
* @class Table
* @memberOf LiveView
* @param {String} name The name of the table.
* @param {String} group The group the table belongs to.
* @param {String} shortDescription A short description of the table. Ideal for length-limited fields.
* @param {String} description A full description of the table.
* @param {boolean} isEnabled A flag indicating whether or not the table is enabled.
* @param {String} queryLanguages A CSV string of supported query languages for this table.
* @param {Array} keys Field names of key fields
* @param {LiveView.Schema} schema The Schema that defines the table fields.
*/
function Table(name, group, shortDescription, description, isEnabled, queryLanguages, keys, schema){
if(!(this instanceof Table)){
return new Table(name, group, shortDescription, description, isEnabled, queryLanguages, keys, schema);
}
/**
* The name of the table.
* @memberOf LiveView.Table
* @instance
* @member {String} name
*/
this.name = name;
/**
* The group the table belongs to.
* @memberOf LiveView.Table
* @instance
* @member {String} group
*/
this.group = group;
/**
* A short description of the table. Ideal for length-limited fields.
* @memberOf LiveView.Table
* @instance
* @member {String} shortDescription
*/
this.shortDescription = shortDescription;
/**
* A full description of the table.
* @memberOf LiveView.Table
* @instance
* @member {String} description
*/
this.description = description;
/**
* A flag indicating whether or not the table is enabled.
* @memberOf LiveView.Table
* @instance
* @member {boolean} isEnabled
*/
this.isEnabled = isEnabled;
/**
* A CSV string of supported query languages for this table.
* @memberOf LiveView.Table
* @instance
* @member {String} queryLanguages
*/
this.queryLanguages = queryLanguages;
/**
* An array of string field names identifying the table's key fields.
* @memberOf LiveView.Table
* @instance
* @member {Array} keys
*/
this.keys = keys;
/**
* The {@link LiveView.Schema|Schema} for the table.
* @memberOf LiveView.Table
* @instance
* @member {LiveView.Schema} schema
*/
this.schema = schema;
}
/** @alias LiveView.Table.prototype */
Table.prototype = {
constructor: Table
};
/**
* Object that defines a LiveView query.
* @class Query
* @memberOf LiveView
* @param {String} query The optionally-parametrized query string
* @param {Object} [parameters] A key-value map of parameters to use to compute the query string, if query is a parametrized string. Users are essentially free to define the key value used to identify a parameter as they wish. The query string is generated using regular expression substitution, so avoidance of regular expression special characters is recommended as it will likely cause unexpected behavior. The '@' character as a parameter prefix works well (e.g. <span style="lvCode">{'@priceMin':100, '@lastUpdated':1415230518223}</span>).
* @param {boolean} [includeInternal] A flag indicating whether or not to include internal fields in (non-aggregate) query results.
*/
function Query(query, parameters, includeInternal){
if(!(this instanceof Query)){
return new Query(query, parameters, includeInternal);
}
/**
* The query string in parametrized form. For example: <span class="lvCode">"Select * From ItemsSales Where lastSoldPrice > @minPrice"</span>
* @memberOf LiveView.Query
* @instance
* @member {String} query
*/
this.query = query;
/**
* A key-value map of parameters to use to compute the query string, if query is a parametrized string. Users are essentially free to define the key value used to identify a parameter as they wish. The query string is generated using regular expression substitution, so avoidance of regular expression special characters is recommended as it will likely cause unexpected behavior. The '@' character as a parameter prefix works well (e.g. <span style="lvCode">{'@priceMin':100, '@lastUpdated':1415230518223}</span>).
* @memberOf LiveView.Query
* @instance
* @member {Object} parameters
*/
this.parameters = parameters;
/**
* A flag indicating whether or not to include internal fields in (non-aggregate) query results.
* @memberOf LiveView.Query
* @instance
* @member {String} includeInternal
*/
this.includeInternal = includeInternal;
}
/** @alias LiveView.Query.prototype */
Query.prototype = {
constructor: Query,
/**
* Applies parameters to the query and returns the resulting query string. If this is not a parametrized query,
* this will be equivalent to the query field.
* @function
* @memberOf LiveView.Query.prototype
* @returns {String} -- The parameter-applied query string
*/
getQueryString: function(){
var key,
escapedKey,
queryString = this.query;
for(key in this.parameters){
if(this.parameters.hasOwnProperty(key)){
//we need to escape the key which could contain special characters, we need to treat them as literals
escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
queryString = queryString.replace(new RegExp(escapedKey, 'g'), this.parameters[key]);
}
}
return queryString;
},
/**
* Formats the query string as required by the LiveView server.
* @function
* @memberOf LiveView.Query.prototype
* @returns {String} -- The parameter-applied, server-formatted query string
*/
serialize: function(){
return this.getQueryString.call(this).replace(/^delete\sfrom\s/i ,'SELECT * FROM ').replace(/^delete/i,'SELECT * FROM ');
}
};
/**
* A LiveView Schema is used for Queries and Tables to define their respective schemas.
* @class Schema
* @memberOf LiveView
* @param {String} name The name of the schema
* @param {Array} fields Array of {@link LiveView.Field|fields} that compose the schema.
*/
function Schema(name, fields){
var i;
if(!(this instanceof Schema)){
return new Schema(name, fields);
}
/**
* Name of the Schema.
* @memberOf LiveView.Schema
* @instance
* @member {String} name
*/
this.name = name;
/**
* The fields that define this schema as an array. The array preserves field order as received from the
* LiveView server.
* @memberOf LiveView.Schema
* @instance
* @member {Array} fields
*/
this.fields = fields;
/**
* The fields that define this schema mapped by field name. The order of fields in the field map may not be
* consistent with the actual schema ordering. The fields array maintains fields in the correct order.
* @memberOf LiveView.Schema
* @instance
* @member {Object<String, LiveView.Field>} fieldsMap
*/
this.fieldsMap = {};
for(i = 0; i < fields.length; i++){
this.fieldsMap[fields[i].name] = fields[i];
}
}
/** @alias LiveView.Schema.prototype */
Schema.prototype = {
constructor: Schema
};
/**
* Defines the properties of a LiveView Field.
* @class Field
* @memberOf LiveView
* @param {String} name The field name. This is used as the unique identifier for this field.
* @param {String} description A description of the field.
* @param {String} type The type of the field (e.g "string", "int", etc).
* @param {LiveView.Schema} [schema] The schema of this field if its type is "tuple".
*/
function Field(name, description, type, schema){
if(!(this instanceof Field)){
return new Field(name, description, type, schema);
}
/**
* The field name. This is used as the unique identifier for this field.
* @memberOf LiveView.Field
* @instance
* @member {String} name
*/
this.name = name;
/**
* A full length description of the field.
* @memberOf LiveView.Field
* @instance
* @member {String} description
*/
this.description = description;
/**
* The type of the field (e.g "string", "int", etc).
* @memberOf LiveView.Field
* @instance
* @member {String} type
*/
this.type = type;
/**
* The schema of this field if its type is "tuple".
* @memberOf LiveView.Field
* @instance
* @member {LiveView.Schema} schema
*/
this.schema = schema;
}
/** @alias LiveView.Field.prototype */
Field.prototype = {
constructor: Field
};
/**
*
* @class Tuple
* @memberOf LiveView
* @param {Number} id The tuple's unique ID
* @param {Object} fieldMap Map of fieldName -> fieldValue
*/
function Tuple(id, fieldMap){
if(!(this instanceof Tuple)){
return new Tuple(id, fieldMap);
}
/**
* The tuple's unique ID
* @memberOf LiveView.Tuple
* @instance
* @member {Number} id
*/
this.id = id;
/**
* Map of fieldName -> fieldValue for all fields in the tuple. Note that the order of fields in the map will not
* necessarily correspond to the order of fields in the corresponding schema. One should refer to the
* {@link LiveView.Schema#fields|fields} array of the corresponding schema to obtain the correct ordering of
* fields.
* @memberOf LiveView.Tuple
* @instance
* @member {Object} fieldMap
*/
this.fieldMap = fieldMap;
}
Tuple.prototype = {
constructor: Tuple
};
/**
* LiveView error object that will be passed as an argument to error handling callbacks and promise rejection
* handlers. LiveView.Error inherits from window.Error if available.
* @class Error
* @memberOf LiveView
* @param {Number} code The error code that identifies the error.
* @param {String} detail A detailed message about what happened.
* @param {String} message A brief description summarizing the error.
* @constructor
*/
function Error(code, detail, message){
var envErr;
if(!(this instanceof Error)){
return new Error(code, detail, message);
}
if(typeof(code) === 'object'){
detail = code.detail || '';
message = code.message || '';
code = code.code || null;
}
//Add useful error info to our LiveView.Error from the native Error object (some values won't be set)
if(typeof(window.Error) === 'function'){
envErr = new window.Error(message);
/**
* The error stack trace if available in the current browser.
* @memberOf LiveView.Error
* @instance
* @member {String} stack
*/
this.stack = envErr.stack;
}
//TODO: Enumerate error codes and update Error creations to use appropriate code
/**
* The error code that identifies the error.
* @memberOf LiveView.Error
* @instance
* @member {Number} code
*/
this.code = code;
/**
* A detailed message about what happened.
* @memberOf LiveView.Error
* @instance
* @member {String} detail
*/
this.detail = detail;
/**
* A brief description summarizing the error.
* @memberOf LiveView.Error
* @instance
* @member {String} message
*/
this.message = message;
}
tmpPrototype = {
constructor: Error,
toString: function(){
return JSON.stringify(this);
}
};
if(window.Error.prototype){
Error.prototype = jQuery.extend(Object.create(window.Error.prototype), tmpPrototype); //so LiveView.Error instance of Error is true
}
else{
Error.prototype = tmpPrototype;
}
}(window, jQuery));