zkjson 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/circomlibjs.js +40504 -0
- package/collection.js +35 -0
- package/db.js +70 -0
- package/encoder.js +458 -0
- package/index.js +5 -0
- package/package.json +7 -0
package/collection.js
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
const newMemEmptyTrie = require("./circomlibjs").newMemEmptyTrie
|
2
|
+
const { pad, str2val, val2str, id2str, encode, str2id } = require("./encoder")
|
3
|
+
|
4
|
+
class Collection {
|
5
|
+
constructor(size = 16) {
|
6
|
+
this.size = size
|
7
|
+
}
|
8
|
+
async init() {
|
9
|
+
this.tree = await newMemEmptyTrie()
|
10
|
+
}
|
11
|
+
async insert(_key, _val) {
|
12
|
+
const doc = encode(_val)
|
13
|
+
const id = str2id(_key)
|
14
|
+
const val = pad(val2str(doc), this.size)
|
15
|
+
return await this.tree.insert(id, val)
|
16
|
+
}
|
17
|
+
async update(_key, _val) {
|
18
|
+
const doc = encode(_val)
|
19
|
+
const id = str2id(_key)
|
20
|
+
const val = pad(val2str(doc), this.size)
|
21
|
+
return await this.tree.update(id, val)
|
22
|
+
}
|
23
|
+
|
24
|
+
async delete(_key) {
|
25
|
+
const id = str2id(_key)
|
26
|
+
return await this.tree.delete(id)
|
27
|
+
}
|
28
|
+
|
29
|
+
async get(_key) {
|
30
|
+
const id = str2id(_key)
|
31
|
+
return await this.tree.find(id)
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
module.exports = Collection
|
package/db.js
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
const newMemEmptyTrie = require("./circomlibjs").newMemEmptyTrie
|
2
|
+
const { str2val, val2str, id2str, encode, str2id } = require("./encoder")
|
3
|
+
const Collection = require("./collection")
|
4
|
+
|
5
|
+
class DB {
|
6
|
+
constructor(size = 16) {
|
7
|
+
this.size = size
|
8
|
+
}
|
9
|
+
async init() {
|
10
|
+
this.tree = await newMemEmptyTrie()
|
11
|
+
this.cols = {}
|
12
|
+
}
|
13
|
+
async addCollection(_key) {
|
14
|
+
const id = str2id(_key)
|
15
|
+
const col = await this.tree.find(id)
|
16
|
+
if (col.found) throw Error("collection exists")
|
17
|
+
const _col = new Collection(this.size)
|
18
|
+
await _col.init()
|
19
|
+
this.cols[_key] = _col
|
20
|
+
const root = _col.tree.F.toObject(_col.tree.root).toString()
|
21
|
+
await this.tree.insert(id, [root])
|
22
|
+
}
|
23
|
+
getColTree(col) {
|
24
|
+
const _col = this.cols[col]
|
25
|
+
if (!_col) throw Error("collection doesn't exist")
|
26
|
+
return _col
|
27
|
+
}
|
28
|
+
async insert(col, _key, _val) {
|
29
|
+
const _col = this.getColTree(col)
|
30
|
+
let update = false
|
31
|
+
let res_doc
|
32
|
+
if ((await _col.get(_key)).found) {
|
33
|
+
update = true
|
34
|
+
res_doc = await _col.update(_key, _val)
|
35
|
+
} else {
|
36
|
+
res_doc = await _col.insert(_key, _val)
|
37
|
+
}
|
38
|
+
const res_col = await this.updateDB(_col, col)
|
39
|
+
return { update, doc: res_doc, col: res_col, tree: _col.tree }
|
40
|
+
}
|
41
|
+
async updateDB(_col, col) {
|
42
|
+
const root = _col.tree.F.toObject(_col.tree.root).toString()
|
43
|
+
const colD = str2id(col)
|
44
|
+
return await this.tree.update(colD, [root])
|
45
|
+
}
|
46
|
+
async update(col, _key, _val) {
|
47
|
+
const _col = this.getColTree(col)
|
48
|
+
const res_doc = await _col.update(_key, _val)
|
49
|
+
const res_col = await this.updateDB(_col, col)
|
50
|
+
return { doc: res_doc, col: res_col, tree: _col.tree }
|
51
|
+
}
|
52
|
+
|
53
|
+
async delete(col, _key) {
|
54
|
+
const _col = this.getColTree(col)
|
55
|
+
const res_doc = await _col.delete(_key)
|
56
|
+
const res_col = await this.updateDB(_col, col)
|
57
|
+
return { doc: res_doc, col: res_col, tree: _col.tree }
|
58
|
+
}
|
59
|
+
|
60
|
+
async get(col, _key) {
|
61
|
+
const _col = this.getColTree(col)
|
62
|
+
return await _col.get(_key)
|
63
|
+
}
|
64
|
+
async getCol(_key) {
|
65
|
+
const id = str2id(_key)
|
66
|
+
return await this.tree.find(id)
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
module.exports = DB
|
package/encoder.js
ADDED
@@ -0,0 +1,458 @@
|
|
1
|
+
const { splitEvery, flatten } = require("ramda")
|
2
|
+
const base64Map = {
|
3
|
+
A: "00",
|
4
|
+
B: "01",
|
5
|
+
C: "02",
|
6
|
+
D: "03",
|
7
|
+
E: "04",
|
8
|
+
F: "05",
|
9
|
+
G: "06",
|
10
|
+
H: "07",
|
11
|
+
I: "08",
|
12
|
+
J: "09",
|
13
|
+
K: "10",
|
14
|
+
L: "11",
|
15
|
+
M: "12",
|
16
|
+
N: "13",
|
17
|
+
O: "14",
|
18
|
+
P: "15",
|
19
|
+
Q: "16",
|
20
|
+
R: "17",
|
21
|
+
S: "18",
|
22
|
+
T: "19",
|
23
|
+
U: "20",
|
24
|
+
V: "21",
|
25
|
+
W: "22",
|
26
|
+
X: "23",
|
27
|
+
Y: "24",
|
28
|
+
Z: "25",
|
29
|
+
a: "26",
|
30
|
+
b: "27",
|
31
|
+
c: "28",
|
32
|
+
d: "29",
|
33
|
+
e: "30",
|
34
|
+
f: "31",
|
35
|
+
g: "32",
|
36
|
+
h: "33",
|
37
|
+
i: "34",
|
38
|
+
j: "35",
|
39
|
+
k: "36",
|
40
|
+
l: "37",
|
41
|
+
m: "38",
|
42
|
+
n: "39",
|
43
|
+
o: "40",
|
44
|
+
p: "41",
|
45
|
+
q: "42",
|
46
|
+
r: "43",
|
47
|
+
s: "44",
|
48
|
+
t: "45",
|
49
|
+
u: "46",
|
50
|
+
v: "47",
|
51
|
+
w: "48",
|
52
|
+
x: "49",
|
53
|
+
y: "50",
|
54
|
+
z: "51",
|
55
|
+
0: "52",
|
56
|
+
1: "53",
|
57
|
+
2: "54",
|
58
|
+
3: "55",
|
59
|
+
4: "56",
|
60
|
+
5: "57",
|
61
|
+
6: "58",
|
62
|
+
7: "59",
|
63
|
+
8: "60",
|
64
|
+
9: "61",
|
65
|
+
"-": "62",
|
66
|
+
_: "63",
|
67
|
+
}
|
68
|
+
|
69
|
+
let strMap = {}
|
70
|
+
for (const k in base64Map) strMap[base64Map[k]] = k
|
71
|
+
|
72
|
+
function pad(arr, max = 0) {
|
73
|
+
arr = arr.map(n => n.toString())
|
74
|
+
for (let i = arr.length; i < max; i++) {
|
75
|
+
arr.push("0")
|
76
|
+
}
|
77
|
+
return arr
|
78
|
+
}
|
79
|
+
|
80
|
+
function encodePath(path) {
|
81
|
+
const parts = []
|
82
|
+
let str = ""
|
83
|
+
let num = 0
|
84
|
+
for (const s of path) {
|
85
|
+
if (num === 2 && !(s === "." || s === "[")) throw Error()
|
86
|
+
if (s === ".") {
|
87
|
+
if (num === 2) {
|
88
|
+
num = 0
|
89
|
+
} else {
|
90
|
+
parts.push(str)
|
91
|
+
str = ""
|
92
|
+
}
|
93
|
+
} else if (s === "[") {
|
94
|
+
if (num !== 2) {
|
95
|
+
if (str !== "" || parts.length > 0) parts.push(str)
|
96
|
+
str = ""
|
97
|
+
}
|
98
|
+
num = 1
|
99
|
+
} else if (s === "]") {
|
100
|
+
if (num !== 1) throw Error()
|
101
|
+
num = 2
|
102
|
+
if (str === "" || Number.isNaN(+str)) throw Error()
|
103
|
+
parts.push(+str)
|
104
|
+
str = ""
|
105
|
+
} else {
|
106
|
+
str += s
|
107
|
+
}
|
108
|
+
}
|
109
|
+
if (str !== "") parts.push(str)
|
110
|
+
if (parts.length === 0) parts.push("")
|
111
|
+
let encoded = [parts.length]
|
112
|
+
for (const p of parts) {
|
113
|
+
if (typeof p === "number") {
|
114
|
+
encoded = encoded.concat([0, 0, p])
|
115
|
+
} else {
|
116
|
+
let plen = [p.length]
|
117
|
+
if (p.length === 0) plen.push(1)
|
118
|
+
encoded = encoded.concat([
|
119
|
+
...plen,
|
120
|
+
...p.split("").map(c => c.charCodeAt(0)),
|
121
|
+
])
|
122
|
+
}
|
123
|
+
}
|
124
|
+
return encoded
|
125
|
+
}
|
126
|
+
|
127
|
+
function decodePath(path) {
|
128
|
+
let str = ""
|
129
|
+
let p = []
|
130
|
+
let len = path.shift()
|
131
|
+
while (path.length > 0) {
|
132
|
+
const type = path.shift()
|
133
|
+
let val = null
|
134
|
+
if (type === 0) {
|
135
|
+
const type2 = path.shift()
|
136
|
+
if (type2 === 0) {
|
137
|
+
val = [type2, path.shift()]
|
138
|
+
} else {
|
139
|
+
val = [type2]
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
val = []
|
143
|
+
for (let i = 0; i < type; i++) {
|
144
|
+
val.push(path.shift())
|
145
|
+
}
|
146
|
+
}
|
147
|
+
p.push([type, ...val])
|
148
|
+
}
|
149
|
+
let i = 0
|
150
|
+
for (let s of p) {
|
151
|
+
if (s[0] === 0 && s[1] === 0) {
|
152
|
+
str += `[${s[2]}]`
|
153
|
+
} else if (s[0] === 0 && s[1] === 1) {
|
154
|
+
if (str !== "") str += "."
|
155
|
+
} else {
|
156
|
+
str += `${i === 0 ? "" : "."}${s
|
157
|
+
.slice(1)
|
158
|
+
.map(c => String.fromCharCode(c))
|
159
|
+
.join("")}`
|
160
|
+
}
|
161
|
+
i++
|
162
|
+
}
|
163
|
+
return str
|
164
|
+
}
|
165
|
+
|
166
|
+
function flattenPath(path) {
|
167
|
+
let p = [path.length]
|
168
|
+
for (const v of path) {
|
169
|
+
p = p.concat(v)
|
170
|
+
}
|
171
|
+
return p
|
172
|
+
}
|
173
|
+
|
174
|
+
function _encode(v, path = []) {
|
175
|
+
let vals = []
|
176
|
+
if (typeof v === "number") {
|
177
|
+
vals.push([path, encodeVal(v)])
|
178
|
+
} else if (typeof v === "boolean") {
|
179
|
+
vals.push([path, encodeVal(v)])
|
180
|
+
} else if (v === null) {
|
181
|
+
vals.push([path, encodeVal(v)])
|
182
|
+
} else if (typeof v === "string") {
|
183
|
+
vals.push([path, encodeVal(v)])
|
184
|
+
} else if (Array.isArray(v)) {
|
185
|
+
let i = 0
|
186
|
+
for (const v2 of v) {
|
187
|
+
for (const v3 of _encode(v2, [...path, [0, 0, i]])) vals.push(v3)
|
188
|
+
i++
|
189
|
+
}
|
190
|
+
} else if (typeof v === "object") {
|
191
|
+
for (const k in v) {
|
192
|
+
const key = k.split("").map(c => c.charCodeAt(0))
|
193
|
+
for (let v4 of _encode(v[k], [
|
194
|
+
...path,
|
195
|
+
[key.length, ...(key.length === 0 ? [1] : key)],
|
196
|
+
])) {
|
197
|
+
vals.push(v4)
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
return vals
|
202
|
+
}
|
203
|
+
|
204
|
+
function encode(json) {
|
205
|
+
let flattened = _encode(json)
|
206
|
+
|
207
|
+
flattened.sort((a, b) => {
|
208
|
+
const isUndefined = v => typeof v === "undefined"
|
209
|
+
const max = Math.max(a[0].length, b[0].length)
|
210
|
+
if (max > 0) {
|
211
|
+
for (let i = 0; i < max; i++) {
|
212
|
+
const exA = !isUndefined(a[0][i])
|
213
|
+
const exB = !isUndefined(b[0][i])
|
214
|
+
if (exA && !exB) return 1
|
215
|
+
if (!exA && exB) return -1
|
216
|
+
const max2 = Math.max(a[0][i].length, b[0][i].length)
|
217
|
+
if (max2 > 0) {
|
218
|
+
for (let i2 = 0; i2 < max2; i2++) {
|
219
|
+
const vA = a[0][i][i2]
|
220
|
+
const vB = b[0][i][i2]
|
221
|
+
const exA = !isUndefined(vA)
|
222
|
+
const exB = !isUndefined(vB)
|
223
|
+
if (exA && !exB) return 1
|
224
|
+
if (!exA && exB) return -1
|
225
|
+
if (vA > vB) return 1
|
226
|
+
if (vA < vB) return -1
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
}
|
231
|
+
return 0
|
232
|
+
})
|
233
|
+
|
234
|
+
return flattened.reduce(
|
235
|
+
(arr, v) => arr.concat([...flattenPath(v[0]), ...v[1]]),
|
236
|
+
[]
|
237
|
+
)
|
238
|
+
}
|
239
|
+
|
240
|
+
function _decode(arr) {
|
241
|
+
let vals = []
|
242
|
+
while (arr.length > 0) {
|
243
|
+
let plen = arr.shift()
|
244
|
+
let keys = []
|
245
|
+
let val = null
|
246
|
+
while (plen > 0) {
|
247
|
+
const plen2 = arr.shift()
|
248
|
+
if (plen2 === 0) {
|
249
|
+
const plen3 = arr.shift()
|
250
|
+
if (plen3 === 1) {
|
251
|
+
keys.push([plen2, plen3])
|
252
|
+
} else {
|
253
|
+
keys.push([plen2, plen3, arr.shift()])
|
254
|
+
}
|
255
|
+
} else if (plen2 !== 0) {
|
256
|
+
const plen3 = plen2
|
257
|
+
const key = []
|
258
|
+
for (let i2 = 0; i2 < plen3; i2++) key.push(arr.shift())
|
259
|
+
keys.push([plen2, ...key])
|
260
|
+
}
|
261
|
+
plen--
|
262
|
+
}
|
263
|
+
const type = arr.shift()
|
264
|
+
val = [type]
|
265
|
+
if (type === 2) {
|
266
|
+
val.push(arr.shift())
|
267
|
+
val.push(arr.shift())
|
268
|
+
val.push(arr.shift())
|
269
|
+
} else if (type === 1) {
|
270
|
+
val.push(arr.shift())
|
271
|
+
} else if (type === 3) {
|
272
|
+
const strlen = arr.shift()
|
273
|
+
val.push(strlen)
|
274
|
+
for (let i2 = 0; i2 < strlen; i2++) val.push(arr.shift())
|
275
|
+
}
|
276
|
+
vals.push([keys, val])
|
277
|
+
}
|
278
|
+
return vals
|
279
|
+
}
|
280
|
+
|
281
|
+
function encodeVal(v) {
|
282
|
+
let vals = []
|
283
|
+
if (typeof v === "number") {
|
284
|
+
const int = Number.isInteger(v)
|
285
|
+
let moved = 0
|
286
|
+
let num = v
|
287
|
+
while (num % 1 !== 0) {
|
288
|
+
num *= 10
|
289
|
+
moved += 1
|
290
|
+
}
|
291
|
+
vals = v < 0 ? [2, 0, moved, -num] : [2, 1, moved, num]
|
292
|
+
} else if (typeof v === "boolean") {
|
293
|
+
vals = [1, v ? 1 : 0]
|
294
|
+
} else if (v === null) {
|
295
|
+
vals = [0]
|
296
|
+
} else if (typeof v === "string") {
|
297
|
+
vals = [3, v.length, ...v.split("").map(c => c.charCodeAt(0))]
|
298
|
+
}
|
299
|
+
return vals
|
300
|
+
}
|
301
|
+
|
302
|
+
function decodeVal(arr) {
|
303
|
+
const type = arr[0]
|
304
|
+
const _val = arr[1]
|
305
|
+
let val = null
|
306
|
+
if (type === 0) {
|
307
|
+
val = null
|
308
|
+
} else if (type === 1) {
|
309
|
+
val = arr[1] ? true : false
|
310
|
+
} else if (type === 2) {
|
311
|
+
val = (arr[1] === 0 ? -1 : 1) * arr[3]
|
312
|
+
for (let i = 0; i < arr[2]; i++) {
|
313
|
+
val /= 10
|
314
|
+
}
|
315
|
+
} else if (type === 3) {
|
316
|
+
val = arr
|
317
|
+
.slice(2)
|
318
|
+
.map(c => String.fromCharCode(c))
|
319
|
+
.join("")
|
320
|
+
}
|
321
|
+
return val
|
322
|
+
}
|
323
|
+
|
324
|
+
function decode(arr) {
|
325
|
+
const decoded = _decode(arr)
|
326
|
+
let json =
|
327
|
+
decoded[0]?.[0]?.[0]?.[0] === 0 && decoded[0]?.[0]?.[0]?.[1] === 0 ? [] : {}
|
328
|
+
for (const v of decoded) {
|
329
|
+
const keys = v[0].map(v2 => {
|
330
|
+
if (v2[0] === 0) {
|
331
|
+
if (v2[1] === 1) return ""
|
332
|
+
return v2[2]
|
333
|
+
} else {
|
334
|
+
return v2
|
335
|
+
.slice(1)
|
336
|
+
.map(c => String.fromCharCode(c))
|
337
|
+
.join("")
|
338
|
+
}
|
339
|
+
})
|
340
|
+
if (keys.length === 0) {
|
341
|
+
json = decodeVal(v[1])
|
342
|
+
} else {
|
343
|
+
let obj = json
|
344
|
+
let i = 0
|
345
|
+
for (const k of keys) {
|
346
|
+
if (typeof k === "number") {
|
347
|
+
if (typeof keys[i + 1] === "undefined") {
|
348
|
+
obj[k] = decodeVal(v[1])
|
349
|
+
} else {
|
350
|
+
if (typeof obj[k] === "undefined") {
|
351
|
+
if (typeof keys[i + 1] === "string") {
|
352
|
+
obj[k] = {}
|
353
|
+
} else {
|
354
|
+
obj[k] = []
|
355
|
+
}
|
356
|
+
}
|
357
|
+
}
|
358
|
+
} else {
|
359
|
+
if (typeof obj[k] === "undefined") {
|
360
|
+
if (typeof keys[i + 1] === "undefined") {
|
361
|
+
obj[k] = decodeVal(v[1])
|
362
|
+
} else if (typeof keys[i + 1] === "string") {
|
363
|
+
obj[k] = {}
|
364
|
+
} else {
|
365
|
+
obj[k] = []
|
366
|
+
}
|
367
|
+
}
|
368
|
+
}
|
369
|
+
obj = obj[k]
|
370
|
+
i++
|
371
|
+
}
|
372
|
+
}
|
373
|
+
}
|
374
|
+
return json
|
375
|
+
}
|
376
|
+
|
377
|
+
const str2id = str => {
|
378
|
+
return (
|
379
|
+
"1" +
|
380
|
+
str
|
381
|
+
.split("")
|
382
|
+
.map(s => base64Map[s])
|
383
|
+
.join("")
|
384
|
+
)
|
385
|
+
}
|
386
|
+
|
387
|
+
const id2str = id => {
|
388
|
+
id.shift()
|
389
|
+
return splitEvery(2, id)
|
390
|
+
.map(s => strMap[s])
|
391
|
+
.join("")
|
392
|
+
}
|
393
|
+
|
394
|
+
function val2str(arr) {
|
395
|
+
const _arr = flatten(
|
396
|
+
arr.map(n => {
|
397
|
+
let str = splitEvery(8, n.toString().split(""))
|
398
|
+
let i = 0
|
399
|
+
str = str.map(s => {
|
400
|
+
const len = i === str.length - 1 ? s.length : 9
|
401
|
+
i++
|
402
|
+
return len.toString() + s.join("")
|
403
|
+
})
|
404
|
+
return str
|
405
|
+
})
|
406
|
+
)
|
407
|
+
let arrs = []
|
408
|
+
let len = 0
|
409
|
+
let str = ""
|
410
|
+
for (let v of _arr) {
|
411
|
+
if (len + v.length > 76) {
|
412
|
+
len = 0
|
413
|
+
arrs.push(str)
|
414
|
+
str = ""
|
415
|
+
}
|
416
|
+
len += v.length
|
417
|
+
str += v
|
418
|
+
}
|
419
|
+
if (str !== "") arrs.push(str)
|
420
|
+
return arrs
|
421
|
+
}
|
422
|
+
|
423
|
+
function str2val(arr) {
|
424
|
+
let _arr = []
|
425
|
+
let prev = ""
|
426
|
+
for (const s of arr) {
|
427
|
+
let str = s.split("")
|
428
|
+
while (str.length > 0) {
|
429
|
+
const len = +str.shift()
|
430
|
+
if (len === 9) {
|
431
|
+
prev += str.slice(0, 8).join("")
|
432
|
+
str = str.slice(8)
|
433
|
+
} else {
|
434
|
+
const nums = str.slice(0, len).join("")
|
435
|
+
str = str.slice(len)
|
436
|
+
_arr.push(+(prev + nums))
|
437
|
+
prev = ""
|
438
|
+
}
|
439
|
+
}
|
440
|
+
}
|
441
|
+
return _arr
|
442
|
+
}
|
443
|
+
|
444
|
+
module.exports = {
|
445
|
+
encode,
|
446
|
+
decode,
|
447
|
+
encodePath,
|
448
|
+
decodePath,
|
449
|
+
encodeVal,
|
450
|
+
decodeVal,
|
451
|
+
pad,
|
452
|
+
_encode,
|
453
|
+
flattenPath,
|
454
|
+
str2id,
|
455
|
+
val2str,
|
456
|
+
str2val,
|
457
|
+
id2str,
|
458
|
+
}
|
package/index.js
ADDED