1 //
  2 // The Antville Project
  3 // http://code.google.com/p/antville
  4 //
  5 // Copyright 2001-2007 by The Antville People
  6 //
  7 // Licensed under the Apache License, Version 2.0 (the ``License'');
  8 // you may not use this file except in compliance with the License.
  9 // You may obtain a copy of the License at
 10 //
 11 //    http://www.apache.org/licenses/LICENSE-2.0
 12 //
 13 // Unless required by applicable law or agreed to in writing, software
 14 // distributed under the License is distributed on an ``AS IS'' BASIS,
 15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16 // See the License for the specific language governing permissions and
 17 // limitations under the License.
 18 //
 19 // $Revision$
 20 // $LastChangedBy$
 21 // $LastChangedDate$
 22 // $URL$
 23 //
 24 
 25 /**
 26  * @fileOverview Defines the Sql prototype, a utility for relational queries
 27  */
 28 
 29 /**
 30  * @constructor
 31  */
 32 var Sql = function() {
 33    var db = getDBConnection("antville");
 34    var query;
 35 
 36    var log = new function() {
 37       var fname = getProperty("sqlLog", "helma." + app.getName() + ".sql");
 38       return Packages.org.apache.commons.logging.LogFactory.getLog(fname);
 39    }
 40 
 41    var SqlData = function(result) {
 42       var columns = [];
 43       this.values = {};
 44       
 45       for (var i=1; i<=result.getColumnCount(); i+=1) {
 46          columns.push(result.getColumnName(i));
 47       }
 48    
 49       this.next = function() {
 50          for each (var key in columns) {
 51             this.values[key] = result.getColumnItem(key);
 52          }
 53          return;
 54       }
 55       
 56       return this;
 57    }
 58 
 59    var quote = function(str) {
 60       if (str === null) {
 61          return str;
 62       }
 63       return "'" + str.replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'";
 64    }
 65 
 66    var value = function(obj) {
 67       if (obj === null) {
 68          return obj;
 69       }
 70       if (obj === undefined) {
 71          obj = String(obj);
 72       }
 73       switch (obj.constructor) {
 74          case Number:
 75          return obj;
 76          case String:
 77          return quote(obj);
 78          case Date:
 79          return "from_unixtime(" + (obj.getTime() / 1000) + ")";
 80          case HopObject:
 81          case Object:
 82          return quote(obj.toSource());
 83       }
 84       return quote(String(obj));
 85    }
 86 
 87    var resolve = function(args) {
 88       var sql = args[0];
 89       if (args.length > 1) {
 90          var values = Array.prototype.splice.call(args, 1);
 91          if (typeof values[0] === "object") {
 92             values = values[0];
 93          }
 94          sql = sql.replace(/\$(\w*)/g, function() {
 95             return value(values[arguments[1]]);
 96          });
 97       }
 98       return sql;
 99    }
100    
101    /**
102     * 
103     * @param {String} sql
104     * @returns {Object}
105     */
106    this.execute = function(sql) {
107       sql = resolve(arguments);
108       log.info(sql);
109       var error;
110       var result = db.executeCommand(sql);
111       if (error = db.getLastError()) {
112          app.log(error);
113       }
114       return result;
115    }
116    
117    /**
118     * @returns {String}
119     */
120    this.retrieve = function() {
121       return log.info(query = resolve(arguments));
122    }
123    
124    /**
125     * 
126     * @param {Function} callback
127     */
128    this.traverse = function(callback) {
129       var rows = db.executeRetrieval(query);
130       if (rows && rows.next()) {
131          do {
132             var sql = new SqlData(rows);
133             sql.next();
134             callback.call(sql.values, rows);
135          } while (record = rows.next());
136          rows.release();
137       }
138       return;
139    }
140    
141    /**
142     * @return {String}
143     */
144    this.toString = function() {
145       return query;
146    }
147    
148    return this;
149 }
150