PageRenderTime 24ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/public/javascripts/lib/html5sql.js

https://bitbucket.org/sce9sc-team/nodebackbone
JavaScript | 329 lines | 299 code | 10 blank | 20 comment | 13 complexity | 9753d6952b3c1302db7b8bad71588ff9 MD5 | raw file
  1. /* ***** html5sql.js ******
  2. *
  3. * Description: A helper javascript module for creating and working with
  4. * HTML5 Web Databases.
  5. *
  6. * License: MIT license <http://www.opensource.org/licenses/mit-license.php>
  7. *
  8. * Authors: Ken Corbett Jr
  9. *
  10. * Version 0.9.2
  11. *
  12. */
  13. var html5sql = (function () {
  14. var readTransactionAvailable = false,
  15. doNothing = function () {},
  16. emptyArray = [],
  17. trim = function (string) {
  18. return string.replace(/^\s+/, "").replace(/\s+$/, "");
  19. },
  20. isArray = function (obj) { // From Underscore.js
  21. return Object.prototype.toString.call(obj) === '[object Array]';
  22. },
  23. isUndefined = function(obj) { // From Underscore.js
  24. return obj === void 0;
  25. },
  26. SelectStmtMatch = new RegExp('^select\\s', 'i'),
  27. isSelectStmt = function (sqlstring) {
  28. return SelectStmtMatch.test(sqlstring);
  29. },
  30. doNothing = function(){},
  31. // transaction is an sql transaction, sqlObjects are properly formated
  32. // and cleaned SQL objects
  33. sqlProcessor = function (transaction, sqlObjects, finalSuccess, failure) {
  34. var sequenceNumber = 0,
  35. dataForNextTransaction = null,
  36. currentSqlObject = null,
  37. runTransaction = function () {
  38. transaction.executeSql(sqlObjects[sequenceNumber].sql,
  39. sqlObjects[sequenceNumber].data,
  40. successCallback,
  41. failureCallback);
  42. },
  43. successCallback = function (transaction, results) {
  44. var i, max, rowsArray = [];
  45. if(html5sql.logInfo){
  46. console.log("Success processing: " + sqlObjects[sequenceNumber].sql);
  47. }
  48. //Process the results of a select puting them in a much more manageable array form.
  49. if(html5sql.putSelectResultsInArray && isSelectStmt(sqlObjects[sequenceNumber].sql)){
  50. for(i = 0, max = results.rows.length; i < max; i++){
  51. rowsArray[i] = results.rows.item(i);
  52. }
  53. } else {
  54. rowsArray = null;
  55. }
  56. //Call the success callback provided with sql object
  57. //If an array of data is returned use that data as the
  58. //data attribute of the next transaction
  59. dataForNextTransaction = sqlObjects[sequenceNumber].success(transaction, results, rowsArray);
  60. sequenceNumber++;
  61. if (dataForNextTransaction && $.isArray(dataForNextTransaction)) {
  62. sqlObjects[sequenceNumber].data = dataForNextTransaction;
  63. dataForNextTransaction = null;
  64. } else {
  65. dataForNextTransaction = null;
  66. }
  67. if (sqlObjects.length > sequenceNumber) {
  68. runTransaction();
  69. } else {
  70. finalSuccess(transaction, results, rowsArray);
  71. }
  72. },
  73. failureCallback = function (transaction, error) {
  74. if(html5sql.logErrors){
  75. console.error("Error: " + error.message + " while processing statment "+(sequenceNumber + 1)+": " + sqlObjects[sequenceNumber].sql);
  76. }
  77. failure(error, sqlObjects[sequenceNumber].sql);
  78. };
  79. runTransaction();
  80. },
  81. sqlObjectCreator = function (sqlInput) {
  82. var i;
  83. if (typeof sqlInput === "string") {
  84. trim(sqlInput);
  85. //Separate sql statements by their ending semicolon
  86. sqlInput = sqlInput.split(';');
  87. for(i = 1; i < sqlInput.length; i++){
  88. //Ensure semicolons within quotes are replaced
  89. while(sqlInput[i].split(/["]/gm).length % 2 === 0 ||
  90. sqlInput[i].split(/[']/gm).length % 2 === 0 ||
  91. sqlInput[i].split(/[`]/gm).length % 2 === 0){
  92. sqlInput.splice(i,2,sqlInput[i] + ";" + sqlInput[i+1]);
  93. }
  94. //Add back the semicolon at the end of the line
  95. sqlInput[i] = trim(sqlInput[i]) + ';';
  96. //Get rid of any empty statements
  97. if(sqlInput[i] === ';'){
  98. sqlInput.splice(i, 1);
  99. }
  100. }
  101. }
  102. for (i = 0; i < sqlInput.length; i++) {
  103. //If the array item is only a string format it into an sql object
  104. if (typeof sqlInput[i] === "string") {
  105. sqlInput[i] = {
  106. "sql": sqlInput[i],
  107. "data": [],
  108. "success": doNothing
  109. };
  110. } else {
  111. if(isUndefined(sqlInput[i].data)){
  112. sqlInput[i].data = [];
  113. }
  114. if(isUndefined(sqlInput[i].success)){
  115. sqlInput[i].success = doNothing;
  116. }
  117. // Check to see that the sql object is formated correctly.
  118. if (typeof sqlInput[i] !== "object" ||
  119. typeof sqlInput[i].sql !== "string" ||
  120. typeof sqlInput[i].success !== "function" ||
  121. !$.isArray(sqlInput[i].data)) {
  122. throw new Error("Malformed sql object: "+sqlInput[i]);
  123. }
  124. }
  125. }
  126. return sqlInput;
  127. },
  128. statementsAreSelectOnly = function (SQLObjects) {
  129. // Returns true if all SQL statement objects are SELECT statements.
  130. var i = 0;
  131. //Loop over SQL objects ensuring they are select statments
  132. do {
  133. //If the sql string is not a select statement return false
  134. if (!isSelectStmt(SQLObjects[i].sql)) {
  135. return false;
  136. }
  137. i++;
  138. } while (i < SQLObjects.length);
  139. //If all the statments happen to be select statments return true
  140. return true;
  141. };
  142. return {
  143. database: null,
  144. logInfo: false,
  145. logErrors: false,
  146. defaultFailureCallback: doNothing,
  147. putSelectResultsInArray: true,
  148. openDatabase: function (name, displayname, size, whenOpen) {
  149. html5sql.database = openDatabase(name, "", displayname, size);
  150. readTransactionAvailable = typeof html5sql.database.readTransaction === 'function';
  151. if (whenOpen) {
  152. whenOpen();
  153. }
  154. },
  155. process: function (sqlInput, finalSuccessCallback, failureCallback) {
  156. /*
  157. *
  158. * Arguments:
  159. *
  160. * sql = [array SQLObjects] ~ collection of SQL statement objects
  161. * or
  162. * [array SQLStrings] ~ collection of SQL statement strings
  163. * or
  164. * "SQLstring" ~ SQL string to be split at the ';'
  165. * character and processed sequentially
  166. *
  167. * finalSuccessCallback = (function) ~ called after all sql statments have
  168. * been processed. Optional.
  169. *
  170. * failureCallback = (function) ~ called if any of the sql statements
  171. * fails. A default one is used if none
  172. * is provided.
  173. *
  174. *
  175. * SQL statement object:
  176. * {
  177. * sql: "string", !Required! ~ Your sql as a string
  178. * data: [array], Optional ~ The array of data to be sequentially
  179. * inserted into your sql at the ?
  180. * success: (function), Optional ~ A function to be called if this
  181. * individual sql statment succeeds.
  182. * If an array is returned it is used as
  183. * the data for the next sql statement
  184. * processed.
  185. * }
  186. *
  187. * Usage:
  188. * html5sql.process(
  189. * [{
  190. * sql: "SELECT * FROM table;",
  191. * data: [],
  192. * success: function(){}
  193. * },
  194. * {
  195. * sql: "SELECT * FROM table;",
  196. * data: [],
  197. * success: function(){}
  198. * }],
  199. * function(){},
  200. * function(){}
  201. * );
  202. *
  203. */
  204. if (html5sql.database) {
  205. var sqlObjects = sqlObjectCreator(sqlInput);
  206. if(isUndefined(finalSuccessCallback)){
  207. finalSuccessCallback = doNothing;
  208. }
  209. if(isUndefined(failureCallback)){
  210. failureCallback = html5sql.defaultFailureCallback;
  211. }
  212. if (statementsAreSelectOnly(sqlObjects) && readTransactionAvailable) {
  213. html5sql.database.readTransaction(function (transaction) {
  214. sqlProcessor(transaction, sqlObjects, finalSuccessCallback, failureCallback);
  215. });
  216. } else {
  217. html5sql.database.transaction(function (transaction) {
  218. sqlProcessor(transaction, sqlObjects, finalSuccessCallback, failureCallback);
  219. });
  220. }
  221. } else {
  222. // Database hasn't been opened.
  223. if(html5sql.logErrors){
  224. console.error("Error: Database needs to be opened before sql can be processed.");
  225. }
  226. return false;
  227. }
  228. },
  229. changeVersion: function (oldVersion, newVersion, sqlInput, finalSuccessCallback, failureCallback) {
  230. /* This is the same as html5sql.process but used when you want to change the
  231. * version of your database. If the database version matches the oldVersion
  232. * passed to the function the statements passed to the funciton are
  233. * processed and the version of the database is changed to the new version.
  234. *
  235. * Arguments:
  236. * oldVersion = "String" ~ the old version to upgrade
  237. * newVersion = "String" ~ the new version after the upgrade
  238. * sql = [array SQLObjects] ~ collection of SQL statement objects
  239. * or
  240. * [array SQLStrings] ~ collection of SQL statement strings
  241. * or
  242. * "SQLstring" ~ SQL string to be split at the ';'
  243. * character and processed sequentially
  244. *
  245. * finalSuccessCallback = (function) ~ called after all sql statments have
  246. * been processed. Optional.
  247. *
  248. * failureCallback = (function) ~ called if any of the sql statements
  249. * fails. A default one is used if none
  250. * is provided.
  251. *
  252. * SQL statement object:
  253. * {
  254. * sql: "string", !Required! ~ Your sql as a string
  255. * data: [array], Optional ~ The array of data to be sequentially
  256. * inserted into your sql at the ?
  257. * success: (function), Optional ~ A function to be called if this
  258. * individual sql statment succeeds
  259. * failure: (function), Optional ~ A function to be called if this
  260. * individual sql statement fails
  261. * }
  262. *
  263. * Usage:
  264. * html5sql.changeVersion(
  265. * "1.0",
  266. * "2.0",
  267. * [{
  268. * sql: "SELECT * FROM table;",
  269. * data: [],
  270. * success: function(){},
  271. * failure: function(){}
  272. * },
  273. * {
  274. * sql: "SELECT * FROM table;",
  275. * data: [],
  276. * success: function(){},
  277. * failure: function(){}
  278. * }],
  279. * function(){},
  280. * function(){}
  281. * );
  282. *
  283. */
  284. if (html5sql.database) {
  285. if(html5sql.database.version === oldVersion){
  286. var sqlObjects = sqlObjectCreator(sqlInput);
  287. if(isUndefined(finalSuccessCallback)){
  288. finalSuccessCallback = doNothing;
  289. }
  290. if(isUndefined(failureCallback)){
  291. failureCallback = html5sql.defaultFailureCallback;
  292. }
  293. html5sql.database.changeVersion(oldVersion, newVersion, function (transaction) {
  294. sqlProcessor(transaction, sqlObjects, finalSuccessCallback, failureCallback);
  295. });
  296. }
  297. } else {
  298. // Database hasn't been opened.
  299. if(html5sql.logErrors){
  300. console.log("Error: Database needs to be opened before sql can be processed.");
  301. }
  302. return false;
  303. }
  304. }
  305. };
  306. })();