├── src ├── .DS_Store ├── utils.ts ├── hash.ts ├── index.ts ├── set.ts ├── base.ts ├── zset.ts ├── mise.ts └── list.ts ├── assets ├── mindb.png └── banner.js ├── examples ├── editor │ ├── assets │ │ ├── icomoon.eot │ │ ├── icomoon.ttf │ │ ├── icomoon.woff │ │ ├── icomoon.svg │ │ ├── editor.css │ │ └── marked.min.js │ ├── flow │ │ ├── 000.html │ │ ├── 003.js │ │ ├── 004.js │ │ ├── 005.js │ │ ├── 006.js │ │ ├── 007.js │ │ ├── 001.html │ │ └── 002.html │ └── index.html ├── AppManager │ ├── t00.js │ ├── mem.js │ ├── t01.js │ ├── t02.js │ ├── index.html │ ├── t03.js │ ├── messages.js │ ├── session.js │ ├── t04.js │ └── main.js ├── stores │ ├── multilevel │ │ ├── server.js │ │ ├── client.js │ │ └── nano_multilevel.js │ ├── IndexedDB │ │ ├── app.js │ │ ├── indexed.js │ │ └── events.js │ ├── adobeair │ │ ├── app.js │ │ └── airstore.js │ ├── LevelDB │ │ ├── co.js │ │ ├── package.json │ │ ├── run.js │ │ ├── min-level.js │ │ ├── logger.js │ │ ├── vender.js │ │ └── tcp_service.js │ ├── memoryStore │ │ ├── mem.src.js │ │ └── mem.js │ ├── Store.js │ │ └── app.js │ └── node_with_file │ │ ├── package.json │ │ ├── app.js │ │ └── filestore.js └── pm2_5 │ └── assets │ ├── moment_zh-cn.js │ ├── async.min.js │ └── pure-min.css ├── .npmignore ├── types ├── utils.d.ts ├── zset.d.ts ├── set.d.ts ├── list.d.ts ├── hash.d.ts ├── base.d.ts ├── mise.d.ts └── index.d.ts ├── .gitignore ├── tsconfig.json ├── webpack.config.js ├── package.json ├── README_zhcn.md ├── README.md └── History.md /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwillwen/mindb/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /assets/mindb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwillwen/mindb/HEAD/assets/mindb.png -------------------------------------------------------------------------------- /examples/editor/assets/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwillwen/mindb/HEAD/examples/editor/assets/icomoon.eot -------------------------------------------------------------------------------- /examples/editor/assets/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwillwen/mindb/HEAD/examples/editor/assets/icomoon.ttf -------------------------------------------------------------------------------- /examples/editor/assets/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iwillwen/mindb/HEAD/examples/editor/assets/icomoon.woff -------------------------------------------------------------------------------- /examples/AppManager/t00.js: -------------------------------------------------------------------------------- 1 | (function(undefined) { 2 | var AppManagerCore = { 3 | addNewApp: function(url, name, callback) { 4 | } 5 | }; 6 | })(); 7 | -------------------------------------------------------------------------------- /examples/editor/flow/000.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Markdown Editor - NanoDB 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | pids 12 | logs 13 | results 14 | doc 15 | test/assets/* 16 | 17 | node_modules 18 | coverage.html 19 | **.txt 20 | npm_debug.log 21 | .git 22 | .dropbox -------------------------------------------------------------------------------- /types/utils.d.ts: -------------------------------------------------------------------------------- 1 | export declare function isObject(obj: any): boolean; 2 | export declare function arrayUnique(array: any[]): any[]; 3 | export declare function arrayInter(array: any[], ...rest: any[]): any[]; 4 | export declare function arrayDiff(array: any[], ...rest: any[]): any[]; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | lib-cov 3 | *.seed 4 | *.log 5 | *.csv 6 | *.dat 7 | *.out 8 | *.pid 9 | *.gz 10 | 11 | pids 12 | logs 13 | results 14 | doc 15 | test/assets/* 16 | 17 | node_modules 18 | coverage.html 19 | **.txt 20 | npm_debug.log 21 | .gitignore 22 | .npmignore 23 | .dropbox -------------------------------------------------------------------------------- /examples/stores/multilevel/server.js: -------------------------------------------------------------------------------- 1 | var net = require('net'); 2 | var multilevel = require('multilevel'); 3 | var level = require('level'); 4 | var db = level('/tmp/test.db', { encoding: 'json' }); 5 | 6 | net.createServer(function(stream) { 7 | stream.pipe(multilevel.server(db)).pipe(stream); 8 | }).listen(8080); -------------------------------------------------------------------------------- /examples/stores/IndexedDB/app.js: -------------------------------------------------------------------------------- 1 | min.store = new IndexedStore('myapp'); 2 | 3 | min.multi() 4 | .incr('user_id') 5 | .incr('user_id') 6 | .incr('user_id') 7 | .exec(function(err, results) { 8 | if (err) { 9 | return console.error(err); 10 | } 11 | 12 | console.dir(results); 13 | }); -------------------------------------------------------------------------------- /examples/stores/adobeair/app.js: -------------------------------------------------------------------------------- 1 | nano.store = new EncryptedLocalStore(); 2 | 3 | nano.multi() 4 | .incr('user_id') 5 | .incr('user_id') 6 | .incr('user_id') 7 | .exec(function(err, results) { 8 | if (err) { 9 | return console.error(err); 10 | } 11 | 12 | console.dir(results); 13 | }); -------------------------------------------------------------------------------- /examples/stores/LevelDB/co.js: -------------------------------------------------------------------------------- 1 | var co = require('co'); 2 | var min = require('../../../'); 3 | var LevelStore = require('./min-level'); 4 | 5 | min.store = new LevelStore('./db'); 6 | 7 | co(function *() { 8 | yield min.set('foo', 'bar'); 9 | var value = yield min.get('foo'); 10 | 11 | console.log(value); //=> bar 12 | })(); -------------------------------------------------------------------------------- /assets/banner.js: -------------------------------------------------------------------------------- 1 | var pkg = require('../package.json') 2 | 3 | var version = pkg.version 4 | 5 | exports.banner = 6 | "MinDB (version " + version + ") - Database on JavaScript\n\n" + 7 | 8 | "Will Wen Gunn(iwillwen) and other contributors\n\n" + 9 | 10 | "@license MIT-license\n" + 11 | "@copyright 2012-2018 iwillwen(willwengunn@gmail.com)" 12 | -------------------------------------------------------------------------------- /examples/editor/flow/003.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | (function($, global) { 3 | // Markdown Editor 4 | var editor = new Editor(); 5 | 6 | // Elements 7 | var $saveBtn = $('#save'); 8 | var $statusOut = $('#status'); 9 | var $markdown = $('#markdown'); 10 | var $title = $('#title'); 11 | })(jQuery, window); 12 | 13 | function noop() { return false; } -------------------------------------------------------------------------------- /examples/stores/memoryStore/mem.src.js: -------------------------------------------------------------------------------- 1 | class MemStore { 2 | constructor() { 3 | this.data = {} 4 | this.ready = true 5 | } 6 | 7 | set(key, value) { 8 | this.data[key] = value 9 | } 10 | 11 | get(key) { 12 | return this.data[key] 13 | } 14 | 15 | remove(key) { 16 | delete this.data[key] 17 | } 18 | } 19 | 20 | export default MemStore 21 | -------------------------------------------------------------------------------- /examples/stores/Store.js/app.js: -------------------------------------------------------------------------------- 1 | require([ 'nano', 'store.js' ], function(nano, store) { 2 | nano.store = store; 3 | 4 | nano.multi() 5 | .incr('user_id') 6 | .incr('user_id') 7 | .incr('user_id') 8 | .exec(function(err, results) { 9 | if (err) { 10 | return console.error(err); 11 | } 12 | 13 | console.dir(results); 14 | }); 15 | }); -------------------------------------------------------------------------------- /examples/stores/LevelDB/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "min-level", 3 | "version": "0.0.1", 4 | "description": "LevelDB StoreInterface for MinDB", 5 | "main": "min-level.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "mindb", 11 | "leveldb" 12 | ], 13 | "author": "iwillwen", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/AppManager/mem.js: -------------------------------------------------------------------------------- 1 | function MemStore() { 2 | this.data = {} 3 | this.ready = true 4 | } 5 | 6 | MemStore.prototype.set = function(key, value) { 7 | this.data[key] = value 8 | } 9 | 10 | MemStore.prototype.get = function(key) { 11 | return this.data[key] 12 | } 13 | 14 | MemStore.prototype.remove = function(key) { 15 | delete this.data[key] 16 | } 17 | 18 | module.exports = MemStore -------------------------------------------------------------------------------- /examples/stores/node_with_file/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "min-file", 3 | "version": "1.0.0", 4 | "description": "FileStore of MinDB in Node.js/Io.js", 5 | "main": "filestore.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "mindb", 11 | "file" 12 | ], 13 | "author": "iwillwen", 14 | "license": "MIT" 15 | } 16 | -------------------------------------------------------------------------------- /examples/stores/multilevel/client.js: -------------------------------------------------------------------------------- 1 | var nano = require('../../nano'); 2 | var MultiLevelStore = require('./nano_multilevel'); 3 | 4 | nano.store = new MultiLevelStore('localhost', 8080); 5 | 6 | nano.multi() 7 | .sadd('foo', 'bar') 8 | .sadd('foo', 'test') 9 | .smembers('foo') 10 | .exec(function(err, results) { 11 | if (err) { 12 | return console.error(err); 13 | } 14 | 15 | console.dir(results[2][0]); 16 | }); -------------------------------------------------------------------------------- /examples/stores/node_with_file/app.js: -------------------------------------------------------------------------------- 1 | var min = require('../../dist/min'); 2 | var FileStore = require('./filestore'); 3 | 4 | min.store = new FileStore(__dirname + '/mydata.db'); 5 | 6 | min.multi() 7 | .sadd('foo', 'bar') 8 | .sadd('foo', 'test') 9 | .smembers('foo') 10 | .exec(function(err, results) { 11 | if (err) { 12 | return console.error(err); 13 | } 14 | 15 | console.dir(results[2][0]); 16 | }); -------------------------------------------------------------------------------- /examples/stores/adobeair/airstore.js: -------------------------------------------------------------------------------- 1 | // For Adobe AIR EncryptedLocalStore 2 | function EncryptedLocalStore() {} 3 | EncryptedLocalStore.prototype.get = function(key) { 4 | return air.EncryptedLocalStore.getItem(key); 5 | }; 6 | EncryptedLocalStore.prototype.set = function(key, value) { 7 | return air.EncryptedLocalStore.setItem(key, value); 8 | }; 9 | EncryptedLocalStore.prototype.remove = function(key) { 10 | return air.EncryptedLocalStore.removeItem(key); 11 | }; -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es5", "es2015", "dom"], 4 | "rootDir": "./src", 5 | "outDir": "./dist/", 6 | "noImplicitAny": true, 7 | "module": "commonjs", 8 | "target": "es5", 9 | "sourceMap": true, 10 | "declaration": true, 11 | "declarationDir": "./types" 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | "build", 16 | "scripts", 17 | "acceptance-tests", 18 | "webpack", 19 | "jest", 20 | "src/setupTests.ts" 21 | ] 22 | } -------------------------------------------------------------------------------- /examples/stores/LevelDB/run.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | var LevelStore = require('./min_level'); 3 | var Benchmark = require('./benchmark'); 4 | var min = require('./min'); 5 | 6 | min.store = new LevelStore('/tmp/benchmark'); 7 | 8 | var n = 0; 9 | var keys = []; 10 | (function loop() { 11 | var curr = Math.random().toString(32).substr(2); 12 | 13 | min.set('bench-' + curr, curr) 14 | .then(function() { 15 | if (++n < 1e4) { 16 | keys.push(curr); 17 | setTimeout(loop); 18 | } else { 19 | run(); 20 | } 21 | }); 22 | })(); -------------------------------------------------------------------------------- /examples/AppManager/t01.js: -------------------------------------------------------------------------------- 1 | (function(undefined) { 2 | var AppManagerCore = { 3 | addNewApp: function(url, name, callback) { 4 | var app = { 5 | url: url, 6 | name: name 7 | }; 8 | 9 | min.incr('apps:id') 10 | .then(function(id) { 11 | app.id = parseInt(id); 12 | 13 | return min.sadd('apps:ids', id); 14 | }) 15 | .then(function() { 16 | return min.hmset('app:' + app.id, app); 17 | }) 18 | .then( 19 | callback.bind(null, null, app.id), 20 | callback 21 | ); 22 | } 23 | }; 24 | })(); -------------------------------------------------------------------------------- /examples/editor/flow/004.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | (function($, global) { 3 | // Markdown Editor 4 | var editor = new Editor(); 5 | 6 | // Elements 7 | var $saveBtn = $('#save'); 8 | var $statusOut = $('#status'); 9 | var $markdown = $('#markdown'); 10 | var $title = $('#title'); 11 | 12 | // Check the saved content 13 | nano.hgetall('md-example') 14 | .then(function(data) { 15 | $title.val(data.title); 16 | $markdown.val(data.content); 17 | 18 | editor.render($markdown.get(0)); 19 | }) 20 | .fail(function() { 21 | editor.render($markdown.get(0)); 22 | }); 23 | })(jQuery, window); 24 | 25 | function noop() { return false; } -------------------------------------------------------------------------------- /examples/stores/multilevel/nano_multilevel.js: -------------------------------------------------------------------------------- 1 | var level = require('level'); 2 | var multilevel = require('multilevel'); 3 | var net = require('net'); 4 | 5 | function MultiLevelStore(host, port) { 6 | var stream = net.connect(port, host); 7 | 8 | var db = multilevel.client(); 9 | 10 | stream.pipe(db.createRpcStream()).pipe(stream); 11 | this.db = db; 12 | this.async = true; 13 | } 14 | MultiLevelStore.prototype.get = function(key, callback) { 15 | this.db.get(key, callback); 16 | }; 17 | MultiLevelStore.prototype.set = function(key, value, callback) { 18 | this.db.put(key, value, callback); 19 | }; 20 | MultiLevelStore.prototype.remove = function(key, callback) { 21 | this.db.del(key, callback); 22 | }; 23 | 24 | module.exports = MultiLevelStore; -------------------------------------------------------------------------------- /examples/stores/LevelDB/min-level.js: -------------------------------------------------------------------------------- 1 | var level = require('level'); 2 | var events = require('events'); 3 | var util = require('util'); 4 | 5 | function LevelStore(filename, options) { 6 | LevelStore.super_.call(this); 7 | 8 | options = options || {}; 9 | 10 | this.db = level(filename, options); 11 | this.filename = filename; 12 | this.ready = true; 13 | this.async = true; 14 | } 15 | util.inherits(LevelStore, events.EventEmitter); 16 | LevelStore.prototype.get = function(key, callback) { 17 | this.db.get(key, callback); 18 | }; 19 | LevelStore.prototype.set = function(key, value, callback) { 20 | this.db.put(key, value, callback); 21 | }; 22 | LevelStore.prototype.remove = function(key, callback) { 23 | this.db.del(key, callback); 24 | }; 25 | 26 | module.exports = LevelStore; -------------------------------------------------------------------------------- /examples/AppManager/t02.js: -------------------------------------------------------------------------------- 1 | (function(undefined) { 2 | var AppManagerCore = { 3 | addNewApp: function(url, name, callback) { 4 | var app = { 5 | url: url, 6 | name: name 7 | }; 8 | 9 | min.incr('apps:id') 10 | .then(function(id) { 11 | app.id = parseInt(id); 12 | 13 | return min.sadd('apps:ids', id); 14 | }) 15 | .then(function() { 16 | return min.hmset('app:' + app.id, app); 17 | }) 18 | .then( 19 | callback.bind(null, null, app.id), 20 | callback 21 | ); 22 | }, 23 | 24 | removeApp: function(id, callback) { 25 | min.multi() 26 | .srem('apps:ids', id) 27 | .del('app:' + id) 28 | .exec(callback); 29 | } 30 | }; 31 | })(); -------------------------------------------------------------------------------- /examples/AppManager/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AppManager 6 | 7 | 8 |
9 |

Apps:

10 | 12 |
13 |
14 |

New App

15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
23 | 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/editor/flow/005.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | (function($, global) { 3 | // Markdown Editor 4 | var editor = new Editor(); 5 | 6 | // Elements 7 | var $saveBtn = $('#save'); 8 | var $statusOut = $('#status'); 9 | var $markdown = $('#markdown'); 10 | var $title = $('#title'); 11 | 12 | // Check the saved content 13 | nano.hgetall('md-example') 14 | .then(function(data) { 15 | $title.val(data.title); 16 | $markdown.val(data.content); 17 | 18 | editor.render($markdown.get(0)); 19 | }) 20 | .fail(function() { 21 | editor.render($markdown.get(0)); 22 | }); 23 | 24 | // Save 25 | $saveBtn.on('click', function() { 26 | var md = editor.codemirror.getValue(); 27 | var title = $title.val(); 28 | }); 29 | })(jQuery, window); 30 | 31 | function noop() { return false; } -------------------------------------------------------------------------------- /types/zset.d.ts: -------------------------------------------------------------------------------- 1 | import { Base } from './base'; 2 | export default class MinSet extends Base { 3 | zadd(key: string, score: number, member: any): Promise<0 | 1>; 4 | zcard(key: string): Promise; 5 | zcount(key: string, min: number, max: number): Promise; 6 | zrem(key: string, ...members: any[]): Promise; 7 | zscore(key: string, member: any): Promise; 8 | zrange(key: string, min: number, max: number): Promise; 9 | zrevrange(key: string, min: number, max: number): Promise; 10 | zincrby(key: string, increment: number, member: any): Promise; 11 | zdecrby(key: string, decrement: number, member: any): Promise; 12 | zrank(key: string, member: any): Promise; 13 | zrevrank(key: string, member: any): Promise; 14 | } 15 | -------------------------------------------------------------------------------- /types/set.d.ts: -------------------------------------------------------------------------------- 1 | import { Base } from './base'; 2 | export default class MinSet extends Base { 3 | sadd(key: string, ...members: any[]): Promise; 4 | srem(key: string, ...members: any[]): Promise; 5 | smembers(key: string): Promise; 6 | sismember(key: string, value: any): Promise; 7 | scard(key: string): Promise; 8 | smove(src: string, dest: string, member: any): Promise; 9 | srandmember(key: string): Promise; 10 | spop(key: string): Promise; 11 | sunion(...keys: string[]): Promise; 12 | sunionstore(dest: string, ...keys: string[]): Promise; 13 | sinter(...keys: string[]): Promise; 14 | sinterstore(dest: string, ...keys: string[]): Promise; 15 | sdiff(...keys: string[]): Promise; 16 | sdiffstore(dest: string, ...keys: string[]): Promise; 17 | } 18 | -------------------------------------------------------------------------------- /examples/editor/flow/006.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | (function($, global) { 3 | // Markdown Editor 4 | var editor = new Editor(); 5 | 6 | // Elements 7 | var $saveBtn = $('#save'); 8 | var $statusOut = $('#status'); 9 | var $markdown = $('#markdown'); 10 | var $title = $('#title'); 11 | 12 | // Check the saved content 13 | nano.hgetall('md-example') 14 | .then(function(data) { 15 | $title.val(data.title); 16 | $markdown.val(data.content); 17 | 18 | editor.render($markdown.get(0)); 19 | }) 20 | .fail(function() { 21 | editor.render($markdown.get(0)); 22 | }); 23 | 24 | // Save 25 | $saveBtn.on('click', function() { 26 | var md = editor.codemirror.getValue(); 27 | var title = $title.val(); 28 | 29 | nano.hmset('md-example', { 30 | title: title, 31 | content: md 32 | }); 33 | }); 34 | 35 | 36 | })(jQuery, window); 37 | 38 | function noop() { return false; } 39 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export function isObject(obj: any) { 2 | return obj === Object(obj) 3 | } 4 | 5 | export function arrayUnique(array: any[]) { 6 | const u: any = {} 7 | const ret: any[] = [] 8 | for (let i = 0, l = array.length; i < l; ++i) { 9 | if (u.hasOwnProperty(array[i]) && !isObject(array[i])) { 10 | continue 11 | } 12 | ret.push(array[i]) 13 | u[array[i]] = 1 14 | } 15 | return ret 16 | } 17 | 18 | export function arrayInter(array: any[], ...rest: any[]) { 19 | return arrayUnique(array).filter(item => { 20 | let ret = true 21 | 22 | for (const other of rest) { 23 | if (other.indexOf(item) < 0) { 24 | ret = false 25 | } 26 | } 27 | 28 | return ret 29 | }) 30 | } 31 | 32 | export function arrayDiff(array: any[], ...rest: any[]) { 33 | let inter = arrayInter(array, ...rest) 34 | let union = arrayUnique(array.concat(...rest)) 35 | return union.filter(item => inter.indexOf(item) < 0) 36 | } -------------------------------------------------------------------------------- /types/list.d.ts: -------------------------------------------------------------------------------- 1 | import { Base } from './base'; 2 | export default class MinList extends Base { 3 | lpush(key: string, ...values: any[]): Promise; 4 | lpushx(key: string, ...values: any[]): Promise; 5 | rpush(key: string, ...values: any[]): Promise; 6 | rpushx(key: string, ...values: any[]): Promise; 7 | lpop(key: string): Promise; 8 | rpop(key: string): Promise; 9 | llen(key: string): Promise; 10 | lrange(key: string, start: number, stop: number): Promise; 11 | lrem(key: string, count: number, value: any): Promise; 12 | lset(key: string, index: number, value: any): Promise; 13 | ltrim(key: string, start: number, stop: number): Promise; 14 | lindex(key: string, index: number): Promise; 15 | linsertBefore(key: string, pivot: any, value: any): Promise; 16 | linsertAfter(key: string, pivot: any, value: any): Promise; 17 | rpoplpush(src: string, dest: string): Promise; 18 | lpoprpush(src: string, dest: string): Promise; 19 | } 20 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 2 | const webpack = require('webpack') 3 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 4 | const b = require('./assets/banner') 5 | const path = require('path') 6 | const os = require('os') 7 | 8 | module.exports = { 9 | entry: './src/index.ts', 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.ts/, 14 | use: 'ts-loader', 15 | exclude: /node_modules/ 16 | } 17 | ] 18 | }, 19 | devtool: 'source-map', 20 | output: { 21 | path: path.resolve(__dirname, 'dist'), 22 | filename: 'min.js', 23 | library: 'min', 24 | libraryTarget: 'umd', 25 | umdNamedDefine: true, 26 | sourceMapFilename: 'min.map' 27 | }, 28 | resolve: { 29 | extensions: [ '.ts' ] 30 | }, 31 | mode: 'production', 32 | optimization: { 33 | usedExports: true, 34 | minimizer: [ 35 | new UglifyJsPlugin({ 36 | parallel: os.cpus().length, 37 | sourceMap: true 38 | }) 39 | ] 40 | }, 41 | plugins: [ 42 | new webpack.BannerPlugin({ 43 | banner: b.banner 44 | }) 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /examples/editor/flow/007.js: -------------------------------------------------------------------------------- 1 | // app.js 2 | (function($, global) { 3 | // Markdown Editor 4 | var editor = new Editor(); 5 | 6 | // Elements 7 | var $saveBtn = $('#save'); 8 | var $statusOut = $('#status'); 9 | var $markdown = $('#markdown'); 10 | var $title = $('#title'); 11 | 12 | // Check the saved content 13 | nano.hgetall('md-example') 14 | .then(function(data) { 15 | $title.val(data.title); 16 | $markdown.val(data.content); 17 | 18 | editor.render($markdown.get(0)); 19 | }) 20 | .fail(function() { 21 | editor.render($markdown.get(0)); 22 | }); 23 | 24 | // Save 25 | $saveBtn.on('click', function() { 26 | var md = editor.codemirror.getValue(); 27 | var title = $title.val(); 28 | 29 | nano.hmset('md-example', { 30 | title: title, 31 | content: md 32 | }) 33 | .then(function() { 34 | $statusOut.text('Saved 已保存,请尝试刷新页面。'); 35 | }) 36 | .fail(function(err) { 37 | $statusOut.text('出错!' + err.message); 38 | }); 39 | }); 40 | 41 | 42 | })(jQuery, window); 43 | 44 | function noop() { return false; } 45 | 46 | // open http://localhost:8080 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "min", 3 | "family": "iwillwen", 4 | "version": "0.2.0", 5 | "description": "Database on JavaScript", 6 | "main": "dist/min.js", 7 | "typings": "types/index.d.ts", 8 | "directories": { 9 | "benchmark": "benchmark", 10 | "example": "examples", 11 | "test": "test" 12 | }, 13 | "scripts": { 14 | "build": "node_modules/.bin/webpack" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/iwillwen/mindb.git" 19 | }, 20 | "keywords": [ 21 | "html5", 22 | "redis", 23 | "database", 24 | "localstorage", 25 | "store" 26 | ], 27 | "author": "iwillwen", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/iwillwen/mindb/issues" 31 | }, 32 | "homepage": "https://github.com/iwillwen/mindb", 33 | "devDependencies": { 34 | "ts-loader": "^5.3.1", 35 | "typescript": "^3.2.1", 36 | "uglify-js": "^2.4.15", 37 | "uglifyjs-webpack-plugin": "^2.0.1", 38 | "webpack": "^4.26.1", 39 | "webpack-cli": "^3.1.2", 40 | "@types/events": "^1.2.0", 41 | "events": "^3.0.0", 42 | "localforage": "^1.7.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /types/hash.d.ts: -------------------------------------------------------------------------------- 1 | import { Base } from './base'; 2 | export default class MinHash extends Base { 3 | hset(key: string, field: string, value: any): Promise; 4 | hsetnx(key: string, field: string, value: any): Promise; 5 | hmset(key: string, doc: { 6 | [field: string]: any; 7 | }): Promise; 8 | hget(key: string, field: string): Promise; 9 | hmget(key: string, fields: string[]): Promise; 10 | hgetall(key: string): Promise<{ 11 | [field: string]: any; 12 | }>; 13 | hdel(key: string, field: string): Promise; 14 | hlen(key: string): Promise; 15 | hkeys(key: string): Promise; 16 | hexists(key: string, field: string): Promise; 17 | hincr(key: string, field: string): Promise; 18 | hincrby(key: string, field: string, increment: number): Promise; 19 | hincrbyfloat(key: string, field: string, increment: number): Promise; 20 | hdecr(key: string, field: string): Promise; 21 | hdecrby(key: string, field: string, decrement: number): Promise; 22 | hdecrbyfloat(key: string, field: string, decrement: number): Promise; 23 | } 24 | -------------------------------------------------------------------------------- /examples/AppManager/t03.js: -------------------------------------------------------------------------------- 1 | (function(undefined) { 2 | var AppManagerCore = { 3 | addNewApp: function(url, name, callback) { 4 | var app = { 5 | url: url, 6 | name: name 7 | }; 8 | 9 | min.incr('apps:id') 10 | .then(function(id) { 11 | app.id = parseInt(id); 12 | 13 | return min.sadd('apps:ids', id); 14 | }) 15 | .then(function() { 16 | return min.hmset('app:' + app.id, app); 17 | }) 18 | .then( 19 | callback.bind(null, null, app.id), 20 | callback 21 | ); 22 | }, 23 | 24 | removeApp: function(id, callback) { 25 | min.multi() 26 | .srem('apps:ids', id) 27 | .del('app:' + id) 28 | .exec(callback); 29 | }, 30 | 31 | listApps: function(callback) { 32 | min.smembers('apps:ids') 33 | .then(function(ids) { 34 | var multi = min.multi(); 35 | 36 | ids.forEach(function(id) { 37 | multi.hgetall('app:' + id); 38 | }); 39 | 40 | multi.exec(function(err, res) { 41 | if (err) return callback(err); 42 | 43 | callback(null, apps); 44 | }) 45 | }, callback); 46 | } 47 | }; 48 | })(); 49 | -------------------------------------------------------------------------------- /examples/stores/LevelDB/logger.js: -------------------------------------------------------------------------------- 1 | var min = require('../../../min'); 2 | var LevelStore = require('./nano_level'); 3 | 4 | min.store = new LevelStore('/tmp/mydb', { encoding: 'json' }); 5 | 6 | var logger = exports; 7 | 8 | logger.log = function(ctx, callback) { 9 | callback = callback || noop; 10 | 11 | return min.incr('log-seq') 12 | .then(function(id) { 13 | return min.hmset('log-' + id, { 14 | type: 'log', 15 | content: ctx, 16 | time: Date.now() 17 | }); 18 | }) 19 | .then(function(key) { 20 | var id = parseInt(key.substr(4)); 21 | 22 | callback(null, id); 23 | }) 24 | .fail(function(err) { 25 | callback(err); 26 | }); 27 | }; 28 | 29 | logger.error = function(err, callback) { 30 | callback = callback || noop; 31 | 32 | return min.incr('log-seq') 33 | .then(function(id) { 34 | return min.hmset('log-' + id, { 35 | type: 'error', 36 | stack: err.stack, 37 | time: Date.now() 38 | }); 39 | }) 40 | .then(function(key) { 41 | var id = parseInt(key.substr(4)); 42 | 43 | callback(null, id); 44 | }) 45 | .fail(function(err) { 46 | callback(err); 47 | }); 48 | }; 49 | 50 | function noop() { 51 | return false; 52 | } -------------------------------------------------------------------------------- /examples/stores/LevelDB/vender.js: -------------------------------------------------------------------------------- 1 | var min = require('../../../min'); 2 | var LevelStore = require('./nano_level'); 3 | var net = require('net'); 4 | var util = require('util'); 5 | 6 | min.store = new LevelStore('/tmp/mydb', { encoding: 'json' }); 7 | 8 | var server = net.createServer(function(stream) { 9 | stream.write(util.format('Simple Redis CLI Simulator: NanoDB with LevelDB on \'%s\'\r\n', min.store.filename)); 10 | stream.write('> '); 11 | 12 | stream.on('data', function(data) { 13 | var args = data.toString().replace(/[\r\n]/g, '').split(' '); 14 | 15 | var command = args.shift().toLowerCase(); 16 | 17 | switch (true) { 18 | // Exit 19 | case command == '\\q': 20 | stream.end('Bye!\n'); 21 | break; 22 | 23 | // Command 24 | case (min.hasOwnProperty(command) && 'function' === typeof min[command]): 25 | min[command].apply(min, args) 26 | .then(function() { 27 | var result = slice.call(arguments).join(' ') + '\n> '; 28 | 29 | stream.write(result); 30 | }) 31 | .fail(function(err) { 32 | stream.write(util.format('(error) ERR %s\n> ', err.messgae)); 33 | }); 34 | break; 35 | 36 | // Unknown command 37 | default: 38 | stream.write(util.format("(error) ERR unknown command '%s'\n> ", command.replace('\n', ''))); 39 | } 40 | }); 41 | 42 | stream.on('error', function(err) { 43 | console.error(err); 44 | }); 45 | }); 46 | 47 | server.listen(8081); 48 | 49 | var slice = [].slice; -------------------------------------------------------------------------------- /examples/stores/LevelDB/tcp_service.js: -------------------------------------------------------------------------------- 1 | var min = require('../../../min'); 2 | var LevelStore = require('./min-level'); 3 | var net = require('net'); 4 | var util = require('util'); 5 | 6 | min.store = new LevelStore('/tmp/mydb', { encoding: 'json' }); 7 | 8 | var server = net.createServer(function(stream) { 9 | stream.write(util.format('Simple Redis CLI Simulator: MinDB with LevelDB on \'%s\'\r\n', min.store.filename)); 10 | stream.write('> '); 11 | 12 | stream.on('data', function(data) { 13 | var args = data.toString().replace(/[\r\n]/g, '').split(' '); 14 | 15 | var command = args.shift().toLowerCase(); 16 | 17 | switch (true) { 18 | // Exit 19 | case command == '\\q': 20 | stream.end('Bye!\n'); 21 | break; 22 | 23 | // Command 24 | case (min.hasOwnProperty(command) && 'function' === typeof min[command]): 25 | min[command].apply(min, args) 26 | .then(function() { 27 | var result = slice.call(arguments).join(' ') + '\n> '; 28 | 29 | stream.write(result); 30 | }) 31 | .fail(function(err) { 32 | stream.write(util.format('(error) ERR %s\n> ', err.messgae)); 33 | }); 34 | break; 35 | 36 | // Unknown command 37 | default: 38 | stream.write(util.format("(error) ERR unknown command '%s'\n> ", command.replace('\n', ''))); 39 | } 40 | }); 41 | 42 | stream.on('error', function(err) { 43 | console.error(err); 44 | }); 45 | }); 46 | 47 | server.listen(8080); 48 | 49 | var slice = [].slice; -------------------------------------------------------------------------------- /examples/stores/node_with_file/filestore.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | var events = require('events') 3 | var util = require('util') 4 | 5 | function FileStore(filename) { 6 | var self = this 7 | 8 | this.filename = filename 9 | this.buffer = {} 10 | 11 | this.async = true 12 | this.ready = false 13 | 14 | fs.exists(filename, function(exists) { 15 | if (!exists) { 16 | fs.writeFile(filename, "{}", function(err) { 17 | if (err) return console.error(err) 18 | 19 | self.ready = true 20 | self.emit('ready') 21 | }) 22 | } else { 23 | fs.readFile(filename, function(err, data) { 24 | if (err) return console.error(err) 25 | 26 | self.buffer = JSON.parse(data.toString()) 27 | 28 | self.ready = true 29 | self.emit('ready') 30 | }) 31 | } 32 | }) 33 | } 34 | util.inherits(FileStore, events.EventEmitter) 35 | FileStore.prototype.set = function(key, value, callback) { 36 | var self = this 37 | 38 | self.buffer[key] = value 39 | 40 | fs.writeFile(self.filename, JSON.stringify(self.buffer), function(err) { 41 | if (err) 42 | return callback(err) 43 | 44 | callback() 45 | }) 46 | } 47 | FileStore.prototype.get = function(key, callback) { 48 | var self = this 49 | 50 | if (self.buffer[key]) { 51 | return callback(null, self.buffer[key]) 52 | } else { 53 | return callback(new Error('This key is not exists.')) 54 | } 55 | } 56 | FileStore.prototype.remove = function(key, callback) { 57 | var self = this 58 | 59 | delete self.buffer[key] 60 | 61 | fs.writeFile(self.filename, JSON.stringify(self.buffer), callback) 62 | } 63 | 64 | module.exports = FileStore -------------------------------------------------------------------------------- /examples/AppManager/messages.js: -------------------------------------------------------------------------------- 1 | // Node shim 2 | if ('undefined' !== typeof process) { 3 | var min = require('min'); 4 | var MemStore = require('./mem'); 5 | min.store = new MemStore(); 6 | } else { 7 | module = { exports: {} }; 8 | } 9 | 10 | var Messages = (function(undefined) { 11 | var Messages = { 12 | pushMessage: function(appId, content, callback) { 13 | var msg = { 14 | content: content 15 | }; 16 | 17 | min.incr('msgs:' + appId + ':id_seq') 18 | .then(function(id) { 19 | msg.id = parseInt(id); 20 | 21 | return min.sadd('msg:' + appId, id); 22 | }) 23 | .then(function() { 24 | return min.set('msg:' + appId + ':' + msg.id, content); 25 | }) 26 | .then(function() { 27 | callback(null, msg.id); 28 | }, callback); 29 | }, 30 | 31 | pullMessages: function(appId, callback) { 32 | min.smembers('msg:' + appId) 33 | .then(function(msgIds) { 34 | return min.mget(msgIds.map(function(id) { 35 | return 'msg:' + appId + ':' + id; 36 | })); 37 | }) 38 | .then(function(msgs) { 39 | return callback(null, msgs); 40 | }, callback); 41 | } 42 | }; 43 | 44 | return Messages; 45 | })(); 46 | 47 | var testMessages = module.exports = function() { 48 | var msgs = [ 49 | 'foo', 50 | 'bar', 51 | 'abc' 52 | ]; 53 | 54 | (function loop(arr) { 55 | var msg = arr.shift(); 56 | 57 | if (!msg) return; 58 | 59 | Messages.pushMessage('test', msg, function(err, id) { 60 | return loop(arr); 61 | }); 62 | })(msgs); 63 | 64 | Messages.pullMessages('test', function(err, res) { 65 | console.dir(res); 66 | }); 67 | }; -------------------------------------------------------------------------------- /types/base.d.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | export declare enum TYPES { 3 | 'mix' = 0, 4 | 'hash' = 1, 5 | 'list' = 2, 6 | 'set' = 3, 7 | 'zset' = 4 8 | } 9 | export declare class Base extends EventEmitter { 10 | name: string; 11 | store: LocalForage; 12 | _keys: { 13 | [key: string]: TYPES; 14 | }; 15 | constructor(name?: string); 16 | _setType(key: string, type: TYPES): Promise; 17 | _delType(key: string): Promise; 18 | _restoreKeys(): Promise; 19 | /** 20 | * Delete a key 21 | * @param {String} key Key 22 | * @return {Promise} Promise 23 | */ 24 | del(key: string): Promise; 25 | /** 26 | * Check a key is exists or not 27 | * @param {String} key Key 28 | * @return {Promise} Promise Object 29 | */ 30 | exists(key: string): Promise; 31 | is(key: string, type: TYPES): Promise; 32 | renamenx(key: string, newKey: string): Promise; 33 | rename(key: string, newKey: string): Promise; 34 | keys(pattern?: string): Promise; 35 | randomKey(): Promise; 36 | type(key: string): Promise; 37 | empty(): Promise; 38 | set(key: string, value: any): Promise; 39 | setnx(key: string, value: any): Promise; 40 | setex(key: string, seconds: number, value: any): Promise; 41 | psetex(key: string, milliseconds: number, value: any): Promise; 42 | mset(doc: { 43 | [key: string]: any; 44 | }): Promise; 45 | append(key: string, value: string): Promise; 46 | get(key: string): Promise; 47 | getrange(key: string, start: number, end: number): Promise; 48 | mget(keys: string[]): Promise; 49 | getset(key: string, value: any): Promise; 50 | strlen(key: string): Promise; 51 | incr(key: string): Promise; 52 | } 53 | -------------------------------------------------------------------------------- /examples/editor/flow/001.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Markdown Editor - NanoDB 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/stores/memoryStore/mem.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | (function (global, factory) { 4 | if (typeof define === "function" && define.amd) { 5 | define(["exports"], factory); 6 | } else if (typeof exports !== "undefined") { 7 | factory(exports); 8 | } else { 9 | var mod = { 10 | exports: {} 11 | }; 12 | factory(mod.exports); 13 | global.memSrc = mod.exports; 14 | } 15 | })(this, function (exports) { 16 | Object.defineProperty(exports, "__esModule", { 17 | value: true 18 | }); 19 | 20 | function _classCallCheck(instance, Constructor) { 21 | if (!(instance instanceof Constructor)) { 22 | throw new TypeError("Cannot call a class as a function"); 23 | } 24 | } 25 | 26 | var _createClass = (function () { 27 | function defineProperties(target, props) { 28 | for (var i = 0; i < props.length; i++) { 29 | var descriptor = props[i]; 30 | descriptor.enumerable = descriptor.enumerable || false; 31 | descriptor.configurable = true; 32 | if ("value" in descriptor) descriptor.writable = true; 33 | Object.defineProperty(target, descriptor.key, descriptor); 34 | } 35 | } 36 | 37 | return function (Constructor, protoProps, staticProps) { 38 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 39 | if (staticProps) defineProperties(Constructor, staticProps); 40 | return Constructor; 41 | }; 42 | })(); 43 | 44 | var MemStore = (function () { 45 | function MemStore() { 46 | _classCallCheck(this, MemStore); 47 | 48 | this.data = {}; 49 | this.ready = true; 50 | } 51 | 52 | _createClass(MemStore, [{ 53 | key: "set", 54 | value: function set(key, value) { 55 | this.data[key] = value; 56 | } 57 | }, { 58 | key: "get", 59 | value: function get(key) { 60 | return this.data[key]; 61 | } 62 | }, { 63 | key: "remove", 64 | value: function remove(key) { 65 | delete this.data[key]; 66 | } 67 | }]); 68 | 69 | return MemStore; 70 | })(); 71 | 72 | exports.default = MemStore; 73 | }); 74 | 75 | -------------------------------------------------------------------------------- /examples/editor/flow/002.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Markdown Editor - MinDB 6 | 7 | 8 | 9 | 10 | 11 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Powered by editor 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /examples/stores/IndexedDB/indexed.js: -------------------------------------------------------------------------------- 1 | window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; 2 | window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; 3 | window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange; 4 | 5 | // IndexedDB Store Interface for NanoDB 6 | function IndexedStore(name) { 7 | var self = this; 8 | self.async = true; 9 | self.storeName = name; 10 | 11 | // Open a database 12 | var req = indexedDB.open(name, 1); 13 | req.onerror = function(event) { 14 | console.error(new Error("Why didn't you allow my web app to use IndexedDB?!")); 15 | }; 16 | req.onsuccess = function(event) { 17 | // Database 18 | self.db = event.target.result; 19 | }; 20 | req.onupgradeneeded = function(event) { 21 | // ObjectStore 22 | self.store = self.db.createObjectStore('nano-' + name, { keyPath: "key" }); 23 | // Ready 24 | self.ready = true; 25 | self.emit('ready'); 26 | }; 27 | } 28 | EventEmitter.inherits(IndexedStore); 29 | IndexedStore.prototype.get = function(key, callback) { 30 | // Fetch the objectstore 31 | var store = this.db 32 | .transaction('nano-' + this.storeName, 'readonly') 33 | .objectStore('nano-' + this.storeName); 34 | 35 | var req = store.get(key); 36 | 37 | req.onerror = function() { 38 | console.error(new Error("Something went wrong!")); 39 | }; 40 | req.onsuccess = function(event) { 41 | var value = event.target.result.value; 42 | 43 | callback(null, value); 44 | }; 45 | }; 46 | IndexedStore.prototype.set = function(key, value, callback) { 47 | var store = this.db 48 | .transaction('nano-' + this.storeName, 'readwrite') 49 | .objectStore('nano-' + this.storeName); 50 | 51 | var req = store.put({ 52 | key: key, 53 | value: value 54 | }); 55 | 56 | req.onerror = function() { 57 | console.error(new Error("Something went wrong!")); 58 | }; 59 | req.onsuccess = function(arguments) { 60 | callback(null, key, value); 61 | }; 62 | }; 63 | IndexedStore.prototype.remove = function(key, callback) { 64 | var store = this.db 65 | .transaction('nano-' + this.storeName, 'readwrite') 66 | .objectStore('nano-' + this.storeName); 67 | 68 | var req = store.delete(key); 69 | 70 | req.onerror = function() { 71 | console.error(new Error("Something went wrong!")); 72 | }; 73 | req.onsuccess = function() { 74 | callback(null, key); 75 | }; 76 | }; -------------------------------------------------------------------------------- /examples/AppManager/session.js: -------------------------------------------------------------------------------- 1 | var wrap = {}; 2 | 3 | Object.defineProperty(wrap, 'session', { 4 | get: function() { 5 | return wrap.$session; 6 | }, 7 | set: function(newValue) { 8 | var changes = objDiff(wrap.$session, newValue); 9 | 10 | var multi = min.multi(); 11 | 12 | for (key in changes) { 13 | if (changes.hasOwnProperty(key)) { 14 | wrap.$session[key] = changes[key]; 15 | multi.set('session:' + key, changes[key]); 16 | } 17 | } 18 | 19 | multi.exec(function(err, res) { 20 | console.log(err, res); 21 | }) 22 | }, 23 | configurable: true 24 | }); 25 | 26 | Object.defineProperty(wrap, '$session', { 27 | get: function() { 28 | return {} 29 | }, 30 | set: function(newValue) { 31 | console.log(newValue); 32 | } 33 | }); 34 | 35 | function objDiff(obj1, obj2) { 36 | var keys1 = Object.keys(obj1); 37 | var keys2 = Object.keys(obj2); 38 | 39 | var diff = arrayDiff(keys2, keys1); 40 | var inter = arrayInter(keys2, keys1); 41 | 42 | console.log(keys1, keys2, diff, inter); 43 | 44 | var changes = {}; 45 | 46 | diff.forEach(function(row) { 47 | changes[row] = obj2[row]; 48 | }); 49 | 50 | inter.forEach(function(row) { 51 | if (obj1[row] !== obj2[row]) { 52 | changes[row] = obj2[row]; 53 | } 54 | }); 55 | 56 | return changes; 57 | } 58 | 59 | function arrayDiff(array) { 60 | var rest = [].slice.call(arguments, 1); 61 | return array.filter(function(item) { 62 | var ret = true; 63 | 64 | for (var i = 0; i < rest.length; i++) { 65 | (function(index) { 66 | var other = rest[index]; 67 | 68 | if (other.indexOf(item) >= 0) { 69 | ret = false; 70 | } 71 | })(i); 72 | } 73 | 74 | return ret; 75 | }); 76 | } 77 | 78 | function arrayInter(array) { 79 | var rest = [].slice.call(arguments, 1); 80 | return arrayUnique(array).filter(function(item) { 81 | var ret = true; 82 | 83 | for (var i = 0; i < rest.length; i++) { 84 | (function(index) { 85 | var other = rest[index]; 86 | 87 | if (other.indexOf(item) < 0) { 88 | ret = false; 89 | } 90 | })(i); 91 | } 92 | 93 | return ret; 94 | }); 95 | } 96 | 97 | function arrayUnique(array) { 98 | var u = {}; 99 | var ret = []; 100 | for (var i = 0, l = array.length; i < l; ++i) { 101 | if (u.hasOwnProperty(array[i]) && !utils.isObject(array[i])) { 102 | continue; 103 | } 104 | ret.push(array[i]); 105 | u[array[i]] = 1; 106 | } 107 | return ret; 108 | } -------------------------------------------------------------------------------- /README_zhcn.md: -------------------------------------------------------------------------------- 1 | ![MinDB](https://raw.githubusercontent.com/iwillwen/mindb/master/assets/mindb.png)**JavaScript 数据库** 2 | 3 | 在 JavaScript 中对你的应用数据进行存储和操作。 4 | MinDB 提供一个标准的存储接口(`Store Interface`)和 **Redis** 风格的 API,你可以在任何 JavaScript 环境中使用。 5 | 6 | # 安装 7 | 8 | 普通`script`标签引入: 9 | 10 | ```html 11 | 8 | 9 | 10 | 11 | 12 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | Powered by editor and MinDB 27 | 28 | 361 | 362 | 363 | -------------------------------------------------------------------------------- /examples/pm2_5/assets/pure-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.3.0 3 | Copyright 2013 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v1.1.2 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v1.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}.pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1.5em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px;-webkit-transition:.1s linear -webkit-box-shadow;-moz-transition:.1s linear -moz-box-shadow;-ms-transition:.1s linear box-shadow;-o-transition:.1s linear box-shadow;transition:.1s linear box-shadow}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-ms-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;font-size:.8em;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-transition:.3s linear border;-moz-transition:.3s linear border;-ms-transition:.3s linear border;-o-transition:.3s linear border;transition:.3s linear border;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border:1px solid #ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em;font-size:90%}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;font-size:125%;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.pure-form-message{display:block;color:#666;font-size:90%}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:80%;padding:.2em 0 .8em}}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-5-24,.pure-u-7-24,.pure-u-11-24,.pure-u-13-24,.pure-u-17-24,.pure-u-19-24,.pure-u-23-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1{width:100%}.pure-u-1-2{width:50%;*width:49.969%}.pure-u-1-3{width:33.3333%;*width:33.3023%}.pure-u-2-3{width:66.6667%;*width:66.6357%}.pure-u-1-4{width:25%;*width:24.969%}.pure-u-3-4{width:75%;*width:74.969%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-1-6{width:16.6667%;*width:16.6357%}.pure-u-5-6{width:83.3333%;*width:83.3023%}.pure-u-1-8{width:12.5%;*width:12.469%}.pure-u-3-8{width:37.5%;*width:37.469%}.pure-u-5-8{width:62.5%;*width:62.469%}.pure-u-7-8{width:87.5%;*width:87.469%}.pure-u-1-12{width:8.3333%;*width:8.3023%}.pure-u-5-12{width:41.6667%;*width:41.6357%}.pure-u-7-12{width:58.3333%;*width:58.3023%}.pure-u-11-12{width:91.6667%;*width:91.6357%}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-g-r{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap}.opera-only :-o-prefocus,.pure-g-r{word-spacing:-.43em}.pure-g-r [class *="pure-u"]{font-family:sans-serif}.pure-g-r img{max-width:100%;height:auto}@media (min-width:980px){.pure-visible-phone{display:none}.pure-visible-tablet{display:none}.pure-hidden-desktop{display:none}}@media (max-width:480px){.pure-g-r>.pure-u,.pure-g-r>[class *="pure-u-"]{width:100%}}@media (max-width:767px){.pure-g-r>.pure-u,.pure-g-r>[class *="pure-u-"]{width:100%}.pure-hidden-phone{display:none}.pure-visible-desktop{display:none}}@media (min-width:768px) and (max-width:979px){.pure-hidden-tablet{display:none}.pure-visible-desktop{display:none}}.pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle;height:2.4em}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:"\25BE"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:6px 12px}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} --------------------------------------------------------------------------------