Skip to content

Commit c0e0800

Browse files
committed
initial
0 parents  commit c0e0800

File tree

12 files changed

+7602
-0
lines changed

12 files changed

+7602
-0
lines changed

.eslintrc.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = {
2+
env: {
3+
es6: true,
4+
node: true
5+
},
6+
extends: [
7+
'standard'
8+
],
9+
globals: {
10+
Atomics: 'readonly',
11+
SharedArrayBuffer: 'readonly'
12+
},
13+
parserOptions: {
14+
ecmaVersion: 2018,
15+
sourceType: 'module'
16+
},
17+
rules: {
18+
}
19+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

.node-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v12.8.1

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v12.8.1

README.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Local JSON Database
2+
3+
This is simple, no dependencies, local disk, table-level Node.js JSON database, which we often use in large development workloads.
4+
5+
## Install
6+
7+
```bash
8+
npm i json-local-db
9+
```
10+
11+
## Fucntions
12+
13+
All functions need `baseDir`, where the database is stored. For example: `join(__dirname, '.data')`.
14+
15+
### Create item in a table
16+
17+
```js
18+
import { create } from 'json-local-db'
19+
await create(baseDir, table, itemName, jsonData).catch((e) => ...)
20+
```
21+
22+
### Read item from the table
23+
24+
```js
25+
import { read } from 'json-local-db'
26+
const jsonData = await read(baseDir, table, itemName).catch((e) => ...)
27+
```
28+
29+
### Update the item in a table
30+
31+
```js
32+
import { update } from 'json-local-db'
33+
await update(baseDir, table, itemName, newJsonData).catch((e) => ...)
34+
```
35+
36+
### Delete item from the table
37+
38+
```js
39+
import { destroy } from 'json-local-db'
40+
await destroy(baseDir, table, itemName).catch((e) => ...)
41+
```
42+
43+
### List table items
44+
45+
```js
46+
import { list } from 'json-local-db'
47+
await list(baseDir, table).catch((e) => ...)
48+
```
49+
50+
### Delete table
51+
52+
```js
53+
import { destroyTable } from 'json-local-db'
54+
await destroyTable(baseDir, table).catch((e) => ...)
55+
```
56+
57+
## Test
58+
59+
```bash
60+
npm run test
61+
```
62+
63+
## Licence
64+
65+
MIT

index.js

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
const { open, unlink, ftruncate, readdir, readFile, stat, writeFile, close, mkdir, rmdir } = require('fs')
2+
const { join } = require('path')
3+
const { promisify } = require('util')
4+
5+
const closeFile = (descriptor, done) => {
6+
close(descriptor, (err) => {
7+
if (!err) {
8+
done(false, {})
9+
} else {
10+
done(`Error closing file: ${err.message}`)
11+
}
12+
})
13+
}
14+
15+
const write = (descriptor, data, done) => {
16+
writeFile(descriptor, data, (err) => {
17+
if (!err) {
18+
closeFile(descriptor, done)
19+
} else {
20+
done(`Error writing file: ${err.message}`)
21+
}
22+
})
23+
}
24+
25+
const stringToJson = (msg, done) => {
26+
try {
27+
done(false, JSON.parse(msg))
28+
} catch (e) {
29+
done(e.message)
30+
}
31+
}
32+
33+
const createTable = (dir, done) => {
34+
mkdir(dir, (err) => {
35+
if (err) {
36+
if (err.code == 'EEXIST') {
37+
done(false)
38+
} else {
39+
done(err)
40+
}
41+
} else {
42+
done(false)
43+
}
44+
})
45+
}
46+
47+
const _create = (baseDir, dir, file, data, done) => {
48+
const dataDir = join(baseDir, dir)
49+
const fileName = join(dataDir, `${file}.json`)
50+
createTable(dataDir, (err) => {
51+
if (!err) {
52+
open(fileName, 'wx', (err, fileDescriptor) => {
53+
if (!err && fileDescriptor) {
54+
const dataString = typeof data === 'string' ? data : JSON.stringify(data)
55+
write(fileDescriptor, dataString, done)
56+
} else {
57+
done('Cannot create new item, it may exist already.')
58+
}
59+
})
60+
} else {
61+
done(`Cannot create table: ${err.message}`)
62+
}
63+
})
64+
}
65+
66+
const _read = (baseDir, dir, file, done) => {
67+
const filePath = join(baseDir, dir, `${file}.json`)
68+
stat(filePath, (err, _) => {
69+
if (!err) {
70+
readFile(filePath, 'utf8', (err, data) => {
71+
if (!err && data) {
72+
stringToJson(data, (err, parsed) => {
73+
if (!err && parsed) {
74+
done(false, parsed)
75+
} else {
76+
done(err)
77+
}
78+
})
79+
} else {
80+
done(err, data)
81+
}
82+
})
83+
} else {
84+
done('No such item or table.')
85+
}
86+
})
87+
}
88+
89+
const _update = (baseDir, dir, file, data, done) => {
90+
open(join(baseDir, dir, `${file}.json`), 'r+', (err, fileDescriptor) => {
91+
if (!err && fileDescriptor) {
92+
const dataString = typeof data === 'string' ? data : JSON.stringify(data)
93+
ftruncate(fileDescriptor, () => {
94+
if (!err) {
95+
write(fileDescriptor, dataString, done)
96+
} else {
97+
done('Error truncating file.')
98+
}
99+
})
100+
} else {
101+
done('Cannot open file for updating, file may not exist.')
102+
}
103+
})
104+
}
105+
106+
const _destroy = (baseDir, dir, file, done) => {
107+
const filepath = join(baseDir, dir, `${file}.json`)
108+
stat(filepath, (err, _) => {
109+
if (!err) {
110+
unlink(filepath, (err) => {
111+
if (!err) {
112+
done(false, {})
113+
} else {
114+
done('Error deleting file.')
115+
}
116+
})
117+
} else {
118+
done('File doens\'t exist.')
119+
}
120+
})
121+
}
122+
123+
const _list = (baseDir, dir, done) => {
124+
const filePath = join(baseDir, dir)
125+
stat(filePath, (err, r) => {
126+
if (err === null) {
127+
readdir(filePath, (err, data) => {
128+
if (!err && data && data.length > 0) {
129+
const out = []
130+
data.forEach((filename) => {
131+
if (filename.indexOf('.json') > -1) {
132+
out.push(filename.replace('.json', ''))
133+
}
134+
})
135+
done(false, out)
136+
} else {
137+
done(err)
138+
}
139+
})
140+
} else {
141+
done(false, [])
142+
}
143+
})
144+
}
145+
146+
const _deleteTable = (baseDir, dir, done) => {
147+
const path = join(baseDir, dir)
148+
_list(baseDir, dir, (err, toDelete) => {
149+
if (!err && toDelete) {
150+
let errors = 0
151+
let i = 1
152+
toDelete.forEach((el) => {
153+
_destroy(baseDir, dir, el, (err, _) => {
154+
if (err) {
155+
errors++
156+
i++
157+
} else {
158+
if (toDelete.length === i && errors === 0) {
159+
try {
160+
stat(path, (err, r) => {
161+
if (err === null) {
162+
rmdir(path, (err) => {
163+
if (err === null) {
164+
done(false)
165+
} else {
166+
done(`Error deleting table: ${err.message} with ${errors} other errrors.`)
167+
}
168+
})
169+
} else {
170+
done(false)
171+
}
172+
})
173+
} catch (e) {
174+
// console.error(e.message)
175+
done(false)
176+
}
177+
}
178+
i++
179+
}
180+
})
181+
})
182+
} else {
183+
done(err)
184+
}
185+
})
186+
}
187+
188+
module.exports.create = promisify(_create)
189+
module.exports.read = promisify(_read)
190+
module.exports.destroy = promisify(_destroy)
191+
module.exports.list = promisify(_list)
192+
module.exports.update = promisify(_update)
193+
module.exports.destroyTable = promisify(_deleteTable)

0 commit comments

Comments
 (0)