aimaier4869 4 years ago
parent
commit
d8378eeec9
3 changed files with 286 additions and 24 deletions
  1. 78 24
      README.md
  2. 182 0
      index.js
  3. 26 0
      package.json

+ 78 - 24
README.md

@@ -1,37 +1,91 @@
 # little-db
 
-#### 介绍
-小型项目的小型本地 JSON 数据库
+> Tiny local JSON database for Node and Electron
+> 小型项目的小型本地 JSON 数据库
 
-#### 软件架构
-软件架构说明
+```js
+// require the little-db
+// 引入little-db
+const db = require('little-db')
 
+// get a database object
+// 得到数据库对象
+const user = db.create('user')
+```
 
-#### 安装教程
+## Install 安装
 
-1.  xxxx
-2.  xxxx
-3.  xxxx
+```
+For the time being, you need to download the installation package manually
+暂时你需要手动下载该包
+```
 
-#### 使用说明
+## Usage 使用
 
-1.  xxxx
-2.  xxxx
-3.  xxxx
+```js
+// require the little-db
+// 引入little-db
+const db = require('little-db')
 
-#### 参与贡献
+// get a database object
+// 得到数据库对象
+const user = db.create('user')
 
-1.  Fork 本仓库
-2.  新建 Feat_xxx 分支
-3.  提交代码
-4.  新建 Pull Request
+// Next, you just need to operate on the user object
+// 接下来你只需要对user对象进行操作即可
 
+// set a property
+// 设置属性
+user.name = 'jack'
+user.age = 18
+user.hobbies = ['eating', 'sleaping', 'playing Peas']
+user.push('fish')
+user.gender = true
+user.address = {
+    country: 'China',
+    city: 'Beijing'
+}
+user.address.city = 'Shanghai'
+```
 
-#### 特技
+```json
+// user.json
+{
+    "name": "jack",
+    "age": 18,
+    "hobbies": [
+        "eating",
+        "sleaping",
+        "playing Peas",
+        "fish"
+    ],
+    "address": {
+        "country": "China",
+        "city": "Shanghai"
+    },
+    "gender": true
+}
+```
 
-1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
-3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
-4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
-5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+```js
+// get a property
+// 读取属性
+user.name // 'jack'
+user.age // 18
+user.hobbies // ['eating', 'sleaping', 'playing Peas']
+user.gender // true
+user.address // {country: 'China', city: 'Beijing'}
+user.address.city // 'Shanghai'
+```
+
+### Methods 方法
+
+### `db.create([dbName, obj, options])`
+* `dbName` {String} File name. If this parameter is not passed in, the current timestamp will be used as the file name. If the file does not exist, a new file will be created. If the file exists, the contents of the file will be read.  文件名,不传入该参数将把当前时间戳作为文件名。文件不存在则会创建一个新文件,若文件存在则读取该文件内容。
+
+* obj {Object} Initial data. If this parameter is passed in, the data will be written to the file. 初始数据,如果传入该参数将把数据写入到文件中。
+
+* options {Object} Configuration object. 配置对象。
+
+  * path {String} Database file storage path. 数据库文件存放路径。It should be an absolute path. 推荐传入一个绝对路径
+    **Default:** `./db/`

+ 182 - 0
index.js

@@ -0,0 +1,182 @@
+const PATH = require('path');
+const fs = require('fs');
+
+let defaultConfig = {
+    path: PATH.resolve('./', 'db')
+}
+
+
+/**
+ * 
+ * @param {String} dbName 文件名
+ * @param {Object} obj 初始数据,若文件存在将会替换内容
+ * @param {Object} config 配置文件
+ * @returns {Proxy} 对象
+ */
+function create(dbName = Date.now() + '', obj, config) {
+    config = { ...defaultConfig, ...config };
+
+    if (typeof dbName !== 'string') throw TypeError('dbName must be string');
+    if (!PATH.isAbsolute(config.path)) throw TypeError('config.path must be a absulute path');
+
+    let totalPath = PATH.resolve(config.path, dbName + '.json');
+
+    // 目录是否存在,不存在创建一个
+    if (!fs.existsSync(config.path)) {
+        fs.mkdirSync(config.path);
+    };
+
+    // 文件是否存在,不存在创建一个
+    if (!fs.existsSync(totalPath)) {
+        fs.closeSync(fs.openSync(totalPath, 'w'));
+        if (!obj) { obj = {} };
+        fs.writeFileSync(totalPath, JSON.stringify(obj));
+    } else {
+        if (obj) {
+            fs.writeFileSync(totalPath, JSON.stringify(obj));
+        } else {
+            obj = JSON.parse(fs.readFileSync(totalPath));
+        }
+    }
+
+
+    const objectList = new WeakMap()//key: target, value: proxy
+
+    // proxyList 避免proxy对象再次被proxy
+    const proxyList = new WeakMap()//key: proxy, value: target
+
+    function reactive(target) {
+        let proxy = objectList.get(target);
+        //如果存在,即返回
+        if (proxy !== void 0) {
+            return proxy
+        }
+        // 如果target是proxy
+        if (proxyList.has(target)) {
+            return target
+        }
+        // 如果是基本类型,直接返回
+        if (!isObject(target)) {
+            return target
+        }
+        proxy = new Proxy(target, handle)
+        objectList.set(target, proxy)
+        proxyList.set(proxy, target)
+
+        return proxy;
+
+    }
+    const handle = { get, set, deleteProperty };
+
+    function get(target, propKey, receiver) {
+        // console.log('get')
+        let proxy = Reflect.get(target, propKey, receiver);
+        track(target, 'get', propKey)
+        return isObject(proxy) ? reactive(proxy) : proxy;
+        //实现多层代理,若为对象,需要递归
+    }
+    function set(target, propKey, value, receiver) {
+        const oldvalue = target[propKey];
+
+        let proxy = Reflect.set(target, propKey, value, receiver)
+        // 当是新增的属性 或者 数据变化时 ,trigger
+        if (!target.hasOwnProperty(propKey)) {
+            trigger(target, 'add', propKey)
+        } else if (oldvalue !== value) {
+            trigger(target, 'set', propKey)
+        }
+
+        fs.writeFileSync(totalPath, JSON.stringify(obj));
+
+        return proxy
+    }
+    function deleteProperty(target, propKey) {
+        // console.log('删除')
+        let proxy = Reflect.deleteProperty(target, propKey)
+        trigger(target, 'delete', propKey)
+
+        fs.writeFileSync(totalPath, JSON.stringify(obj));
+        return proxy
+    }
+
+    //方法
+    function isObject(val) {
+        return typeof val === 'object' && val !== null;
+    }
+
+    //effect.js
+
+    //收集依赖
+    let targetMap = new WeakMap()//所有依赖 key:obj
+
+
+    //get 时 收集依赖
+    function track(target, type, key) {
+        // console.log('track-收集依赖', type, target, key)
+
+        if (effectFn) {
+            let depsMap = targetMap.get(target);
+            //targetMap无target对象,则新建
+            if (depsMap === void 0) {
+                // console.log('无depsMap')
+                targetMap.set(target, (depsMap = new Map()))
+            }
+            //depsMap无有key这个属性,则新建
+            let dep = depsMap.get(key)
+            if (dep === void 0) {
+                // console.log('无key')
+                depsMap.set(key, (dep = new Set()))
+            }
+            // 放入依赖 effect就是依赖
+            if (!dep.has(effectFn)) {
+                // console.log('无effect,并放入effect')
+                dep.add(effectFn)
+            }
+        }
+    }
+
+    //set 时更新
+    function trigger(target, type, key) {
+        // console.log('trigger-触发依赖', type, key)
+
+        let depsMap = targetMap.get(target)
+
+        if (depsMap) {
+            let deps = depsMap.get(key)
+            if (deps) {
+                //将当前key对应的effect一次执行
+                deps.forEach(effect => {
+                    effect()
+                })
+                // 删除
+                if (type == 'delete') {
+                    // console.log('delete')
+                    depsMap.delete(key)
+                }
+            }
+
+        }
+    }
+    //临时存放 effect中的fn参数
+    let effectFn = null;
+
+    function effect(fn) {
+        try {
+            // console.log('try')
+            effectFn = fn;
+            fn();
+        } finally {
+            // console.log('finally')
+            effectFn = null;
+        }
+    }
+
+    return reactive(obj);
+}
+
+
+module.exports = {
+    create
+};
+
+

+ 26 - 0
package.json

@@ -0,0 +1,26 @@
+{
+  "name": "little-db",
+  "version": "1.0.0",
+  "author": "aimaier4869",
+  "description": "Tiny local JSON database for Node and Electron.一个小型本地的JSON数据库",
+  "main": "index.js",
+  "repository": {
+		"type": "git",
+		"url": "https://gitee.com/aimaier4869/little-db.git"
+	},
+  "homepage": "https://gitee.com/aimaier4869/little-db",
+  "bugs": "https://gitee.com/aimaier4869/little-db/issues",
+  "keywords": [
+    "database",
+    "electron",
+    "JSON",
+    "local",
+    "lowdb",
+    "littledb",
+    "reactive",
+    "jsondb",
+    "localStorage"
+  ],
+  "license": "MIT",
+  "engines": {"node": ">=16.0.0"}
+}