antville/code/Global/Sql.js

215 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// The Antville Project
// http://code.google.com/p/antville
//
// Copyright 20012014 by the Workers of Antville.
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileOverview Defines the Sql prototype, a utility for relational queries
*/
/**
* @constructor
*/
var Sql = function(options) {
options || (options = {});
var db = getDBConnection('antville');
var query;
var log = new function() {
var fname = getProperty('sqlLog', 'helma.' + app.getName() + '.sql');
return Packages.org.apache.commons.logging.LogFactory.getLog(fname);
}
var SqlData = function(result) {
var columns = [];
this.values = {};
for (var i=1; i<=result.getColumnCount(); i+=1) {
columns.push(result.getColumnName(i).toLowerCase());
}
this.next = function() {
for each (var key in columns) {
this.values[key] = result.getColumnItem(key);
}
return;
}
return this;
}
var quote = function(str) {
if (!options.quote || str === null) {
return str;
}
return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
}
var value = function(obj) {
if (obj === null) {
return obj;
}
if (obj === undefined) {
obj = String(obj);
}
switch (obj.constructor) {
case Number:
return obj;
case String:
return quote(obj);
case Date:
return 'from_unixtime(' + (obj.getTime() / 1000) + ')';
case HopObject:
case Object:
return quote(obj.toSource());
}
return quote(String(obj));
}
var resolve = function(args) {
var sql = args[0];
if (args.length > 1) {
var values = Array.prototype.splice.call(args, 1);
if (typeof values[0] === 'object') {
values = values[0];
}
sql = sql.replace(/\$(\w*)/g, function() {
return value(values[arguments[1]]);
});
}
return sql;
}
/**
* Executes an SQL command.
* @param {String} sql The SQL command.
* @returns {Object} The result of the SQL command.
*/
this.execute = function(sql) {
sql = resolve(arguments);
log.info(sql);
if (options.test) {
return app.log(sql);
}
var error;
var result = db.executeCommand(sql);
if (error = db.getLastError()) {
app.log(error);
}
return result;
}
/**
* Retrieves an SQL query.
* @example sql.retrieve('select $1 from $2 order by $1', 'date', 'foo')
* ===> 'select date from foo order by date'
* @returns {String}
*/
this.retrieve = function() {
return log.info(query = resolve(arguments));
}
/**
* Traverses over the results of an SQL query.
* @param {Function} callback The callback function executed for each record.
*/
this.traverse = function(callback) {
var rows = db.executeRetrieval(query);
if (rows && rows.next()) {
do {
var sql = new SqlData(rows);
sql.next();
if (!options.test) {
callback.call(sql.values, rows);
}
} while (record = rows.next());
rows.release();
}
return;
}
/**
* @return {String}
*/
this.toString = function() {
return query;
}
return this;
}
/**
* SQL query for retrieving the amount of records in a table.
* @constant
*/
Sql.COUNT = 'select count(*) as count from $0';
/**
* SQL query for retrieving the referrers of a site or a story.
* @constant
*/
Sql.REFERRERS = 'select referrer, count(*) as requests from ' +
"log where context_type = '$0' and context_id = $1 and action = " +
"'main' and created > now() - interval '2 days' group " +
'by referrer order by requests desc, referrer asc';
/**
* SQL command for deleting all log entries older than 2 days.
* @constant
*/
Sql.PURGEREFERRERS = "delete from log where action = 'main' and " +
"created < now() - interval '2 days'";
/**
* SQL query for searching stories.
* @constant
*/
Sql.STORY_SEARCH = "select content.id from content, site, metadata where site.id = $0 and content.prototype = 'Story' and site.id = content.site_id and content.status in ('public', 'shared', 'open') and content.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by content.id, content.created order by content.created desc limit $2";
Sql.COMMENT_SEARCH = "select comment.id from content as comment, content as story, site, metadata where site.id = $0 and comment.prototype = 'Comment' and site.id = comment.site_id and comment.story_id = story.id and story.status in ('public', 'shared', 'open') and story.comment_mode in ('open') and comment.id = metadata.parent_id and metadata.name in ('title', 'text') and lower(metadata.value) like lower('%$1%') group by comment.id, comment.created order by comment.created desc limit $2";
/**
* SQL query for searching accounts which are not already members of the desired site.
* @constant
*/
Sql.MEMBERSEARCH = "select id, name, created from account where name $0 '$1' order by name asc limit $2";
/**
* SQL query for retrieving all story IDs in a sites archive.
* @constant
*/
Sql.ARCHIVE = "select id from content where site_id = $0 and prototype = 'Story' and " +
"status in ('public', 'shared', 'open') $1 $2 limit $3 offset $4";
/**
* SQL command for retrieving the size of a sites archive.
* @constant
*/
Sql.ARCHIVESIZE = 'select count(*) as count from content where site_id = $0 ' +
"and prototype = 'Story' and status in ('public', 'shared', 'open') $1";
/**
* SQL part filtering the archive query.
* @see Archive#getFilter
* @constant
*/
Sql.ARCHIVEPART = ' and extract($0 from created) = $1';
/**
* SQL part for applying an order to the archive query.
* @see Archive#stories_macro
* @constant
*/
Sql.ARCHIVEORDER = 'order by created desc';