浏览 2055 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-04-20
FileDB前两版是基于Java和Servlet容器的,且只能现实简单的Key/Value数据存取。 V3.0版使用了Javascript语言重写代码,并进行了重新设计,运行环境改为了Node.js。 V3.0版功能有所增强,支持建任意多个表,前端还支持简单的SQL语句查询。 使用中建议配合JQuery库一起使用,想test.html中的一样。 数据库相关代码在附件中,感兴趣的同学可以下载下来测试下,也欢迎与我讨论。 数据库代码:
// This class parses the sql statement alike.
// Examples : create table abc; insert into abc(field, field2, field3) values('xxx', 123, 234);
// update abc set field = 'xxx', field2 = 123 where [id] = 123;
// select * from abc where [field] = 'xxx' and ([field2] >= 123 or [field3] < 234) order by field desc limit 0, 20
function Query(sql) {
this.sql = sql.toLowerCase().replace(/\'/g, '"').replace(/;/g, '');
}
Query.prototype.exec = function() {
if (this.sql.indexOf('create') != -1) {
return JSON.stringify(this.create());
} else if (this.sql.indexOf('insert') != -1) {
return JSON.stringify(this.insert());
} else if (this.sql.indexOf('update') != -1) {
return JSON.stringify(this.update());
} else if (this.sql.indexOf('select') != -1) {
return JSON.stringify(this.select());
} else if (this.sql.indexOf('show') != -1) {
var str = '{';
for (var tab in App.db.data) {
str += '"' + tab + '":' + App.db.data[tab].data.length + ',';
}
str = (str.length > 1 ? str.slice(0, -1) : str) + '}';
return str;
} else {
return 'false';
}
};
Query.prototype.create = function() {
var arr = this.sql.match(/table\s+(\w+)/); // regex is : table \s+ (\w+)
if (!arr || arr.length != 2) return false;
if (App.db.get(arr[1])) return false; // already exists.
var tab = new Table(arr[1]);
App.db.set(tab);
return true;
};
Query.prototype.insert = function() {
// regex is : (\w+) \( ([\w\s,]+) \) \s+ values \( ([\w\s,\"]+) \)
var arr = this.sql.match(/(\w+)\s*\(([\w\s,]+)\)\s+values\(([\w\s,\"]+)\)/);
if (!arr || arr.length != 4) return false;
var tab = new Table('rs').init(App.db.get(arr[1]));
var fields = arr[2].split(/\s*,\s*/);
var values = arr[3].split(/\s*,\s*/);
var str = '{';
for (var i = 0; i < fields.length; i++) {
str += '"' + fields[i] + '":' + values[i] + ',';
}
str = str.slice(0, -1) + '}';
var obj = JSON.parse(str);
tab.insert(obj);
Cache.change[arr[1]] = true; File.save();
return true;
};
Query.prototype.update = function() {
// regex is : update \s+ (\w+) \s+ set \s+ ([\w\s,=\'\"]+?) \s+ where \s+ ([\w\s=\[\]\'\"]+)
var arr = this.sql.match(/update\s+(\w+)\s+set\s+([\w\s,=\'\"]+?)\s+where\s+([\w\s=<>\[\]\'\"]+)/);
if (!arr || arr.length != 4) return false;
var tab = new Table('rs').init(App.db.get(arr[1]));
var sets = arr[2].split(/\s*,\s*/);
var rs = tab.select(arr[3]);
for (var i = rs.data.length - 1; i >= 0; i--) {
for (var j = sets.length - 1; j >= 0; j--) {
var kv = sets[j].split(/\s*=+\s*/);
tab.update(rs.data[i].id, kv[0], isNaN(kv[1]) ? kv[1] : parseInt(kv[1]));
}
}
Cache.change[arr[1]] = true; File.save();
return true;
};
Query.prototype.select = function() {
var limit = this.sql.split(/\s+limit\s+/);
var order = limit[0].split(/\s+order\s+by\s+/);
var where = order[0].split(/\s+where\s+/);
var from = where[0].replace(/.+?from\s+/, '');
if (!from.match(/[0-9A-z_]+/)) return false;
if (Cache.change[from]) {
Cache.change[from] = false;
Cache.set(this.sql, null);
}
if (Cache.get(this.sql)) return Cache.get(this.sql);
var tab = new Table('rs').init(App.db.get(from));
tab = tab.select(where[1]).orderby(order[1]).limit(limit[1]);
Cache.set(this.sql, tab);
return tab;
};
exports.Query = Query;
function Cache() {
}
Cache.change = {}; // This property preserved the changed tables.
Cache.data = {}; // This property preserverd the cache data.
Cache.set = function(sql, tab) {
Cache.data[sql] = tab;
}
Cache.get = function(sql) {
return Cache.data[sql];
}
function DB(name) {
this.name = name;
this.data = {};
}
DB.prototype.set = function(tab) {
this.data[tab.name] = tab;
};
DB.prototype.get = function(name) {
return this.data[name];
};
function Table(name) {
this.name = name;
this.data = [];
}
Table.prototype.init = function(json) {
this.name = json.name;
this.data = json.data;
return this;
};
Table.prototype.insert = function(obj) {
obj.id = this.data.length;
this.data.push(obj);
};
Table.prototype.update = function(id, k, v) {
this.data[id][k] = v;
};
Table.prototype.select = function(con) {
var rs = new Table('rs');
if (!con) { rs.data = this.data; return rs; }
con = con.replace(/and/g, '&&').replace(/or/g, '||').replace(/([^<>!=])=\s*/g, '$1 == ');
con = con.replace(/\[\"?\'?(\w+)\"?\'?]/g, "this.data[i]['$1']"); // regex is : \[ \"? \'? (\w+) \"? \'? ]
for (var i = this.data.length - 1; i >= 0; i--) {
try {
if (eval(con)) rs.data.push(this.data[i]);
} catch(e) {
console.log(new Date() + ' : 查询条件解析错误:' + e);
}
}
return rs;
};
Table.prototype.orderby = function(str) {
var rs = new Table('rs');
rs.data = this.data;
if (!str || rs.data.length < 2) return rs;
var strs = str.split(/\s+/);
rs.data.sort(function(a, b) {
if (!isNaN(a[strs[0]]) && !isNaN(b[strs[0]])) {
if (strs[1] && strs[1].toLowerCase() == 'desc') {
return b[strs[0]] - a[strs[0]];
} else {
return a[strs[0]] - b[strs[0]];
}
} else {
if (strs[1] && strs[1].toLowerCase() == 'desc') {
return b[strs[0]].localeCompare(a[strs[0]]);
} else {
return a[strs[0]].localeCompare(b[strs[0]]);
}
}
});
return rs;
};
Table.prototype.limit = function(str) {
var rs = new Table('rs');
rs.data = this.data;
if (!str) return rs;
var strs = str.split(/,/); // separated by ","
if (!strs[1]) { strs[1] = strs[0]; strs[0] = 0; }
rs.data = this.data.slice(parseInt(strs[0]), parseInt(strs[0]) + parseInt(strs[1]));
return rs;
};
function File() {
}
File.read = function(str) {
File.time = new Date().getTime();
var file = new DB('db');
try {
var fs = require('fs');
var dbFile = fs.readFileSync('./' + str + '.txt', 'utf8');
var dbObj = JSON.parse(dbFile);
file.name = dbObj.name;
file.data = dbObj.data;
} catch (e) {
console.log(new Date() + ' : Error : File ' + str + '.txt is not successfully loaded!');
}
return file;
};
File.write = function(db) {
var data = JSON.stringify(db);
var fs = require('fs');
fs.writeFile('./' + db.name + '.txt', data, function (err) {
if (err) console.log(new Date() + ' : Error : ' + db.name + ' is not successfully saved!');
});
};
File.save = function() {
var curTime = new Date().getTime();
if (curTime - File.time > 10000) File.write(App.db); // If > 10s, then saved.
File.time = curTime;
};
function App() {
}
App.run = function() {
App.db = File.read('db'); // Defined a static property named 'db'.
};
exports.run = App.run;
数据库代码二:
var http = require('http'); var url = require('url'); var fs = require('fs'); var path = require('path'); var db = require('./filedb3.js'); var mime = { "css": "text/css", "gif": "image/gif", "html": "text/html", "ico": "image/x-icon", "jpeg": "image/jpeg", "jpg": "image/jpeg", "js": "text/javascript", "json": "application/json", "pdf": "application/pdf", "png": "image/png", "svg": "image/svg+xml", "swf": "application/x-shockwave-flash", "tiff": "image/tiff", "txt": "text/plain", "wav": "audio/x-wav", "wma": "audio/x-ms-wma", "wmv": "video/x-ms-wmv", "xml": "text/xml" }; var server = http.createServer(function(req, res) { if (req.url !== '/favicon.ico') { var urlObj = url.parse(req.url, true); var pathname = urlObj.pathname; if (pathname !== '/db.php') { var realPath = pathname.slice(1); path.exists(realPath, function (exists) { if (!exists) { res.writeHead(404, {'Content-Type': 'text/plain'}); res.write('This request URL ' + pathname + ' was not found on this server.'); res.end(); } else { fs.readFile(realPath, 'binary', function (err, file) { if (err) { res.writeHead(500, {'Content-Type': 'text/plain'}); res.end(err); } else { var ext = path.extname(realPath); ext = ext ? ext.slice(1) : 'unknown'; var contentType = mime[ext] || "text/plain"; res.writeHead(200, {'Content-Type': contentType}); res.write(file, "binary"); res.end(); } }); } }); } else { var query = urlObj.query; res.writeHead(200, {'Content-Type': 'application/json'}); var str = new db.Query(query.sql).exec(); res.write(query.callback + '(' + str + ')'); res.end(); } } else { //res.writeHead(404, {'Content-Type': 'text/plain'}); } }); server.on('error', function(err) { console.log(new Date() + ' : ' + err); }); db.run(); server.listen(8080); console.log(new Date() + ' : Server running at http://localhost:8080/'); 测试代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>FileDB V3.0 测试页面</title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $('input[type="button"]').click(function() { var sql = $.trim($(this).prev().val()); //alert(sql); $.getJSON('http://localhost:8080/db.php?callback=?', {sql : sql}, function(data) { alert(JSON.stringify(data)); //$('#result').html(JSON.stringify(data)); }); }); }); </script> </head> <body> <h1>FileDB V3.0 测试页面</h1> <form id="form1" name="form1" method="post" action=""> <p> <input name="textfield" type="text" value="create table abc" /> <input type="button" name="Submit" value="执行语句" /> </p> <p> <input name="textfield2" type="text" value="insert into abc(name, age, job) values('yfs', 30, 'developer')" size="80" /> <input type="button" name="Submit2" value="执行语句" /> </p> <p> <input name="textfield3" type="text" value="insert into abc(name, age, job) values('why', 28, 'developer')" size="80" /> <input type="button" name="Submit3" value="执行语句" /> </p> <p> <input name="textfield4" type="text" value="insert into abc(name, age, job) values('liyan', 27, 'developer')" size="80" /> <input type="button" name="Submit4" value="执行语句" /> </p> <p> <input name="textfield5" type="text" value="insert into abc(name, age, job) values('lipeng', 31, 'designer')" size="80" /> <input type="button" name="Submit5" value="执行语句" /> </p> <p> <input name="textfield6" type="text" value="select * from abc where [job] = 'developer' and ([age] >= 30 or [age] < 28) order by age desc limit 0, 1" size="120" /> <input type="button" name="Submit6" value="执行语句" /> </p> <p> <input name="textfield7" type="text" value="update abc set name = 'xxx', age = 123 where [name] = 'yfs' or [age] <= 28" size="80" /> <input type="button" name="Submit7" value="执行语句" /> </p> <p> <input name="textfield8" type="text" value="show status" /> <input type="button" name="Submit8" value="执行语句" /> </p> </form> <p id="result"></p> <p>PS :此NoSQL数据库仅支持基本的SQL语句关键字,不支持联合查询和SQL函数及in、like关键字。</p> <p>PS2:where子句字段名需用中括号[]括起来,update语句必须带where子句。</p> </body> </html>
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |