`
treemp3
  • 浏览: 23982 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

基于Node.js的NoSQL产品:FileDB V3.0开发完毕

阅读更多

 

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] &gt;= 30 or [age] &lt; 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] &lt;= 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>
 

 

分享到:
评论

相关推荐

    Node.js-样板:Next.js(React)ExpressRESTAPIMongoDBMongoose-Crudify

    标题中的“Node.js-样板:Next.js(React)ExpressRESTAPIMongoDBMongoose-Crudify”揭示了一个基于Node.js的Web开发项目模板,它整合了几个关键的技术栈,包括Next.js、Express、REST API、MongoDB以及Mongoose。...

    Node.js-基于node.jsMongodb构建的后台系统

    Node.js 是一种基于 Chrome V8 引擎的 JavaScript 运行环境,它允许开发者在服务器端使用 JavaScript 进行编程,极大地拓宽了JavaScript的应用场景。本项目“Node.js-基于node.js Mongodb构建的后台系统”是利用Node...

    基于Vue.js-Node.js-Mongodb 的本人本科毕业设计.zip

    Node.js是一个开放源代码、跨平台的JavaScript运行环境,用于在服务器端执行JavaScript代码。它基于Chrome V8引擎,使得开发者可以用JavaScript编写服务器端程序,打破了传统意义上前后端分离的界限。Node.js采用...

    node.js14.18.3版本下载

    Node.js 使用 V8 引擎,这是 Google 为 Chrome 浏览器开发的高性能 JavaScript 和 WebAssembly 引擎。Node.js 的设计思想是事件驱动、非阻塞 I/O 模型,使其在数据密集型实时应用中表现出色。 标题中的“node.js...

    node-v14.17.0-linux-x64.tar.gz

    Node.js是一款基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript进行开发,极大地扩展了JavaScript的应用范围。 描述中的信息与标题相同,再次确认了这是一个针对Linux平台的Node.js...

    Node.js开发实战 视频教程 下载 因为太大存百度云盘1.zip

    1. **Node.js基础**:Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它允许开发者使用JavaScript进行服务器端编程。讲解可能包括了JavaScript在Node.js中的异步非阻塞I/O模型,事件驱动编程的概念,以及如何...

    Node.js-基于React.jsNode.js的开源博客框架

    【标题】:“Node.js-基于React.js的Node.js开源博客框架” 这个项目是一个结合了Node.js后端技术和React.js前端框架的开源博客平台。它利用了Node.js的非阻塞I/O模型和JavaScript的全栈能力,实现了高效、可扩展的...

    基于Node.js与微信小程序的活动管理平台.zip

    1. **Node.js**:Node.js基于Chrome V8引擎,用JavaScript编写服务器端程序。它的异步I/O模型使得它在处理高并发请求时表现出色,适合构建实时通信应用,如聊天系统、流媒体服务或API服务器。 2. **Express框架**:...

    Node.js-基于Node.js和MongoDB实现的基金小工具

    Node.js是一款基于Chrome V8引擎的JavaScript运行环境,它让JavaScript可以在服务器端执行,打破了JavaScript只能在浏览器中运行的传统。Node.js采用了事件驱动、非阻塞I/O模型,使其在高并发场景下表现出色,非常...

    基于node.js的机房收费管理系统(含数据库脚本).zip

    Node.js是一个流行的开源JavaScript运行环境,它允许开发人员使用JavaScript进行服务器端编程。这个系统不仅适用于大学生的课程设计,对于初学者和专业人士来说,也是一个很好的学习资源,可以深入理解Web应用开发。...

    基于Node.js的极简的学生管理系统

    Node.js,作为一款基于Chrome V8引擎的JavaScript运行环境,以其非阻塞I/O和事件驱动的特性,使得它在构建高效、可扩展的网络应用时展现出强大的性能。本项目“基于Node.js的极简的学生管理系统”就是利用了这些优势...

    Node.js-基于Node.jsExpressejsMongoDBBootstrap搭建的班级博客系统

    标题中的“Node.js-基于Node.js Expressejs MongoDB Bootstrap搭建的班级博客系统”揭示了这个项目的核心技术栈,包括Node.js、Express、ejs模板引擎、MongoDB数据库以及Bootstrap前端框架。接下来,我将详细阐述...

    基于Node.js的部门管理系统的设计与实现

    《基于Node.js的部门管理系统设计与实现》 Node.js,作为一个强大的开源JavaScript运行环境,以其异步非阻塞I/O模型、高效的性能以及丰富的生态系统,成为构建高效网络应用的首选工具。本文将深入探讨如何利用Node....

    基于Node.js的宠物领养系统的设计与实现-源码

    总结,基于Node.js的宠物领养系统利用了JavaScript全栈开发的优势,结合现代化的Web技术和工具,构建了一个功能完善、安全可靠的平台,旨在促进宠物领养的透明度和便利性。在实际开发过程中,开发者应不断学习新技术...

    《Node入门一本全面地Node.js教程》PDF

    Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它允许开发者在服务器端使用JavaScript进行编程。这本《Node入门一本全面地Node.js教程》PDF,是学习Node.js的基础指南,涵盖了从安装到实际项目开发的全方位...

    Node.js 6.x Blueprints(pdf+epub+mobi+code)

    Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它让JavaScript得以在服务器端运行,打破了JavaScript只能在浏览器中使用的限制。Node.js采用单线程、事件驱动的非阻塞I/O模型,使其在高并发场景下表现出色,...

    Node.js-基于nodemongodbexpressejs技术栈搭建的一套完整功能的后台管理系统

    Node.js是一种基于Chrome V8引擎的JavaScript运行环境,它让开发者能够在服务器端使用JavaScript编写代码,极大地推动了前后端同栈开发的潮流。MongoDB是一个流行的NoSQL数据库,以其灵活性和高性能著称,适合处理...

    Node.js-node开发的博客项目

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,它让开发者能够在服务器端使用 JavaScript 进行编程,极大地推动了全栈开发的流行。在这个名为 "Node.js-node开发的博客项目" 的案例中,我们看到的是一...

    nosql, 面向小型 node.js 项目的NoSQL 嵌入式数据库.zip

    nosql, 面向小型 node.js 项目的NoSQL 嵌入式数据库 node.js NoSQL 嵌入数据库 重要: 新版本 has has新版本的新方法 has 。 数据库文件的结构是相同的。与专业支持的在线聊天。支持专业支持 。新: 在线 NoSQL 嵌入式...

Global site tag (gtag.js) - Google Analytics