/** * Simulates a connection to a database by making asynchronous http requests to * a remote PHP script that returns the results in JSON format. * Using this class can perform any operation that can be done with a database, * like open/close a connection or selecion/updating queries. **/ Db.Conn = new Class ().extend ({ Flag: { NOT_NULL : 1 ,PRI_KEY : 2 ,AI : 512 | 2 | 1 } ,Type: { BOOLEAN : 1 ,INTEGER : 2 ,DOUBLE : 3 ,STRING : 4 ,DATE : 8 ,DATE_TIME : 9 } }); Db.Conn.implement ({ Extends: Vn.Object ,connected: false ,requestsCount: 0 /** * Initilizes the connection object. **/ ,initialize: function () { this.parent (); } /** * Opens the connection to the database. * * @param {string} user The user name * @param {String} password The user password * @param {Boolean} remember Specifies if the user should be remembered * @param {Function} openCallback The function to call when operation is done **/ ,open: function (user, pass, remember, openCallback) { this.signalEmit ('loading-changed', true); var request = new Vn.HttpRequest (); request.add ({'action': 'login'}); if (user != null) { request.add ({ 'user': user ,'password': pass ,'remember': remember }); } request.send ('rest.php', this.opened.bind (this, request, openCallback)); } /* * Called when open operation is done. */ ,opened: function (request, openCallback, success) { var openSuccess = false; if (success) try { var json = request.getJson (); openSuccess = true /* json.data */; } catch (e) {} if (openSuccess) this.connected = true; this.signalEmit ('loading-changed', false); if (openCallback) openCallback (this, openSuccess); } /** * Closes the connection to the database. * * @param {Function} closeCallback The function to call when operation is done **/ ,close: function (closeCallback) { this.signalEmit ('loading-changed', true); var request = new Vn.HttpRequest (); request.addValue ({'action': 'close'}); request.send ('rest.php', this.closed.bind (this, closeCallback)); } /* * Called when close operation is done. */ ,closed: function (closeCallback) { this.connected = false; this.signalEmit ('closed'); this.signalEmit ('loading-changed', false); if (closeCallback) closeCallback (this); } /** * Runs a SQL query on the database. * * @param {String} sql The SQL statement * @param {Function} callback The function to call when operation is done **/ ,execSql: function (sql, callback) { this.requestsCount++; if (this.requestsCount == 1) this.signalEmit ('loading-changed', true); var httpRequest = new Vn.HttpRequest () httpRequest.add ({ 'action': 'query' ,'sql': sql }); httpRequest.send ('rest.php', this.execDone.bind (this, httpRequest, callback)); } /** * Runs a stmt on the database. * * @param {Sql.Stmt} stmt The statement * @param {Function} callback The function to call when operation is done * @param {Sql.Batch} batch The batch used to set the parameters **/ ,execStmt: function (stmt, callback, batch) { this.execSql (stmt.render (batch), callback); } /** * Runs a query on the database. * * @param {String} query The SQL statement * @param {Function} callback The function to call when operation is done * @param {Sql.Batch} batch The batch used to set the parameters **/ ,execQuery: function (query, callback, batch) { this.execStmt (new Sql.String ({query: query}), callback, batch); } /* * Parses a value to date. */ ,valueToDate: function (value) { return new Date (value * 1000); } /* * Called when a query is executed. */ ,execDone: function (httpRequest, callback, success) { var e; var error = null; var results = null; this.requestsCount--; if (this.requestsCount == 0) this.signalEmit ('loading-changed', false); if (!success) { error = new Vn.Error ('Conn', 'connError', _('ConnError')); this.signalEmit ('error', error); } else try { var json = httpRequest.getJson (); results = json.data; if (json.error !== null) error = new Vn.Error (json.error.domain, json.error.code, json.error.message); if (results instanceof Array) for (var i = 0; i < results.length; i++) if (results[i] !== true) { var data = results[i].data; var columns = results[i].columns; for (var j = 0; j < columns.length; j++) { var castFunc = null; switch (columns[j].type) { case Db.Conn.Type.DATE: case Db.Conn.Type.DATE_TIME: case Db.Conn.Type.TIMESTAMP: castFunc = this.valueToDate; break; } if (castFunc !== null) { if (columns[j].def != null) columns[j].def = castFunc (columns[j].def); for (var k = 0; k < data.length; k++) if (data[k][j] != null) data[k][j] = castFunc (data[k][j]); } } } } catch (e) { this.signalEmit ('error', e); error = e; } if (callback) try { callback (new Db.ResultSet (results, error)); } catch (e) { this.signalEmit ('error', e); } } });