inibase 1.0.0-rc.20 → 1.0.0-rc.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/dist/file.js +268 -223
- package/dist/index.d.ts +6 -3
- package/dist/index.js +25 -20
- package/dist/utils.js +1 -1
- package/dist/utils.server.d.ts +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,13 +40,6 @@ const users = await db.get("user", { favoriteFoods: "![]Pizza" });
|
|
|
40
40
|
|
|
41
41
|
If you like Inibase, please sponsor: [GitHub Sponsors](https://github.com/sponsors/inicontent) || [Paypal](https://paypal.me/KarimAmahtil).
|
|
42
42
|
|
|
43
|
-
## Sponsors
|
|
44
|
-
|
|
45
|
-
<br>
|
|
46
|
-
<br>
|
|
47
|
-
|
|
48
|
-
Become a sponsor and have your company logo here 👉 [GitHub Sponsors](https://github.com/sponsors/inicontent) || [paypal](https://paypal.me/KarimAmahtil).
|
|
49
|
-
|
|
50
43
|
## Install
|
|
51
44
|
|
|
52
45
|
```js
|
|
@@ -57,6 +50,15 @@ Become a sponsor and have your company logo here 👉 [GitHub Sponsors](https://
|
|
|
57
50
|
|
|
58
51
|
To semplify the idea, each database has tables, each table has columns, each column will be stored in a seperated file. When POSTing new data, it will be appended to each columns file as new line. When GETing data, the file will be readed line-by-line so it can handle large data (without consuming a lot of resources)
|
|
59
52
|
|
|
53
|
+
## Benchmark
|
|
54
|
+
|
|
55
|
+
| | 10 | 100 | 1000 |
|
|
56
|
+
|--------|-------|-------|-------|
|
|
57
|
+
| POST | 23 ms | 20 ms | 83 ms |
|
|
58
|
+
| GET | 12 ms | 16 ms | 45 ms |
|
|
59
|
+
| PUT | 6 ms | 4 ms | 11 ms |
|
|
60
|
+
| DELETE | 18 ms | 21 ms | 27 ms |
|
|
61
|
+
|
|
60
62
|
## Examples
|
|
61
63
|
|
|
62
64
|
<details>
|
package/dist/file.js
CHANGED
|
@@ -118,73 +118,85 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
|
|
|
118
118
|
: input, fieldType, fieldChildrenType, secretKey);
|
|
119
119
|
};
|
|
120
120
|
export const get = async (filePath, lineNumbers, fieldType, fieldChildrenType, secretKey) => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
121
|
+
let fileHandle;
|
|
122
|
+
try {
|
|
123
|
+
fileHandle = await open(filePath, "r");
|
|
124
|
+
const rl = doesSupportReadLines()
|
|
125
|
+
? fileHandle.readLines()
|
|
126
|
+
: createInterface({
|
|
127
|
+
input: fileHandle.createReadStream(),
|
|
128
|
+
crlfDelay: Infinity,
|
|
129
|
+
});
|
|
130
|
+
let lines = new Map(), lineCount = 0;
|
|
131
|
+
if (!lineNumbers) {
|
|
132
|
+
for await (const line of rl)
|
|
133
|
+
lineCount++,
|
|
134
|
+
lines.set(lineCount, decode(line, fieldType, fieldChildrenType, secretKey));
|
|
135
|
+
}
|
|
136
|
+
else if (lineNumbers === -1) {
|
|
137
|
+
let lastLine;
|
|
138
|
+
for await (const line of rl)
|
|
139
|
+
lineCount++, (lastLine = line);
|
|
140
|
+
if (lastLine)
|
|
141
|
+
lines.set(lineCount, decode(lastLine, fieldType, fieldChildrenType, secretKey));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
let lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
145
|
+
for await (const line of rl) {
|
|
146
|
+
lineCount++;
|
|
147
|
+
if (!lineNumbersArray.has(lineCount))
|
|
148
|
+
continue;
|
|
131
149
|
lines.set(lineCount, decode(line, fieldType, fieldChildrenType, secretKey));
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
lineCount++, (lastLine = line);
|
|
137
|
-
if (lastLine)
|
|
138
|
-
lines.set(lineCount, decode(lastLine, fieldType, fieldChildrenType, secretKey));
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
let lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
142
|
-
for await (const line of rl) {
|
|
143
|
-
lineCount++;
|
|
144
|
-
if (!lineNumbersArray.has(lineCount))
|
|
145
|
-
continue;
|
|
146
|
-
lines.set(lineCount, decode(line, fieldType, fieldChildrenType, secretKey));
|
|
147
|
-
lineNumbersArray.delete(lineCount);
|
|
148
|
-
if (!lineNumbersArray.size)
|
|
149
|
-
break;
|
|
150
|
+
lineNumbersArray.delete(lineCount);
|
|
151
|
+
if (!lineNumbersArray.size)
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
150
154
|
}
|
|
155
|
+
return [lines.size ? Object.fromEntries(lines) : null, lineCount];
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
await fileHandle?.close();
|
|
151
159
|
}
|
|
152
|
-
await fileHandle.close();
|
|
153
|
-
return [lines.size ? Object.fromEntries(lines) : null, lineCount];
|
|
154
160
|
};
|
|
155
161
|
export const replace = async (filePath, replacements) => {
|
|
156
162
|
if (await isExists(filePath)) {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
163
|
+
const fileTempPath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`;
|
|
164
|
+
let fileHandle, fileTempHandle, lineCount = 0;
|
|
165
|
+
try {
|
|
166
|
+
fileHandle = await open(filePath, "r");
|
|
167
|
+
fileTempHandle = await open(fileTempPath, "w+");
|
|
168
|
+
const rl = doesSupportReadLines()
|
|
169
|
+
? fileHandle.readLines()
|
|
170
|
+
: createInterface({
|
|
171
|
+
input: fileHandle.createReadStream(),
|
|
172
|
+
crlfDelay: Infinity,
|
|
173
|
+
}), writeStream = fileTempHandle.createWriteStream();
|
|
174
|
+
if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
175
|
+
if (!(replacements instanceof Map))
|
|
176
|
+
replacements = new Map(Object.entries(replacements));
|
|
177
|
+
for await (const line of rl) {
|
|
178
|
+
lineCount++;
|
|
179
|
+
writeStream.write((replacements.has(lineCount.toString())
|
|
180
|
+
? replacements.get(lineCount.toString())
|
|
181
|
+
: line) + "\n");
|
|
182
|
+
}
|
|
183
|
+
const newLinesNumbers = new Set([...replacements.keys()].filter((num) => num > lineCount));
|
|
184
|
+
if (newLinesNumbers.size) {
|
|
185
|
+
if (Math.min(...newLinesNumbers) - lineCount - 1 > 1)
|
|
186
|
+
writeStream.write("\n".repeat(Math.min(...newLinesNumbers) - lineCount - 1));
|
|
187
|
+
for (const newLineNumber of newLinesNumbers)
|
|
188
|
+
writeStream.write(replacements.get(newLineNumber.toString()) + "\n");
|
|
189
|
+
}
|
|
179
190
|
}
|
|
191
|
+
else
|
|
192
|
+
for await (const _line of rl)
|
|
193
|
+
writeStream.write(replacements + "\n");
|
|
194
|
+
await rename(fileTempPath, filePath);
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
await fileHandle?.close();
|
|
198
|
+
await fileTempHandle?.close();
|
|
180
199
|
}
|
|
181
|
-
else
|
|
182
|
-
for await (const _line of rl)
|
|
183
|
-
writeStream.write(replacements + "\n");
|
|
184
|
-
// writeStream.end(async () => await rename(fileTempPath, filePath));
|
|
185
|
-
await fileHandle.close();
|
|
186
|
-
await fileTempHandle.close();
|
|
187
|
-
await rename(fileTempPath, filePath);
|
|
188
200
|
}
|
|
189
201
|
else if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
190
202
|
if (!(replacements instanceof Map))
|
|
@@ -197,61 +209,78 @@ export const replace = async (filePath, replacements) => {
|
|
|
197
209
|
}
|
|
198
210
|
};
|
|
199
211
|
export const append = async (filePath, data, startsAt = 1) => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
writeStream.write(
|
|
212
|
+
let fileHandle;
|
|
213
|
+
try {
|
|
214
|
+
fileHandle = await open(filePath, "a");
|
|
215
|
+
const doesFileExists = await isExists(filePath);
|
|
216
|
+
const writeStream = fileHandle.createWriteStream();
|
|
217
|
+
if (doesFileExists) {
|
|
218
|
+
const currentNumberOfLines = await count(filePath);
|
|
219
|
+
if (startsAt - currentNumberOfLines - 1 > 0)
|
|
220
|
+
writeStream.write("\n".repeat(startsAt - currentNumberOfLines - 1));
|
|
221
|
+
if (Array.isArray(data)) {
|
|
222
|
+
for (const input of data)
|
|
223
|
+
writeStream.write(input + "\n");
|
|
224
|
+
}
|
|
225
|
+
else
|
|
226
|
+
writeStream.write(data + "\n");
|
|
209
227
|
}
|
|
210
|
-
else
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
writeStream.write(
|
|
228
|
+
else {
|
|
229
|
+
if (startsAt - 1 > 0)
|
|
230
|
+
writeStream.write("\n".repeat(startsAt - 1));
|
|
231
|
+
if (Array.isArray(data)) {
|
|
232
|
+
for (const input of data)
|
|
233
|
+
writeStream.write(input + "\n");
|
|
234
|
+
}
|
|
235
|
+
else
|
|
236
|
+
writeStream.write(data + "\n");
|
|
219
237
|
}
|
|
220
|
-
else
|
|
221
|
-
writeStream.write(data + "\n");
|
|
222
238
|
}
|
|
223
|
-
|
|
239
|
+
finally {
|
|
240
|
+
await fileHandle?.close();
|
|
241
|
+
}
|
|
224
242
|
};
|
|
225
243
|
export const remove = async (filePath, linesToDelete) => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
writeStream.
|
|
244
|
+
const fileTempPath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`;
|
|
245
|
+
let fileHandle, fileTempHandle, lineCount = 0;
|
|
246
|
+
try {
|
|
247
|
+
fileHandle = await open(filePath, "r");
|
|
248
|
+
fileTempHandle = await open(fileTempPath, "w+");
|
|
249
|
+
const linesToDeleteArray = new Set(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]), rl = doesSupportReadLines()
|
|
250
|
+
? fileHandle.readLines()
|
|
251
|
+
: createInterface({
|
|
252
|
+
input: fileHandle.createReadStream(),
|
|
253
|
+
crlfDelay: Infinity,
|
|
254
|
+
}), writeStream = fileTempHandle.createWriteStream();
|
|
255
|
+
for await (const line of rl) {
|
|
256
|
+
lineCount++;
|
|
257
|
+
if (!linesToDeleteArray.has(lineCount))
|
|
258
|
+
writeStream.write(`${line}\n`);
|
|
259
|
+
}
|
|
260
|
+
await rename(fileTempPath, filePath);
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
await fileTempHandle?.close();
|
|
264
|
+
await fileHandle?.close();
|
|
237
265
|
}
|
|
238
|
-
// writeStream.end(async () => await rename(fileTempPath, filePath));
|
|
239
|
-
await fileHandle.close();
|
|
240
|
-
await fileTempHandle.close();
|
|
241
|
-
await rename(fileTempPath, filePath);
|
|
242
266
|
};
|
|
243
267
|
export const count = async (filePath) => {
|
|
244
|
-
let lineCount = 0;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
268
|
+
let fileHandle, lineCount = 0;
|
|
269
|
+
try {
|
|
270
|
+
fileHandle = await open(filePath, "r");
|
|
271
|
+
const rl = doesSupportReadLines()
|
|
272
|
+
? fileHandle.readLines()
|
|
273
|
+
: createInterface({
|
|
274
|
+
input: fileHandle.createReadStream(),
|
|
275
|
+
crlfDelay: Infinity,
|
|
276
|
+
});
|
|
277
|
+
for await (const line of rl)
|
|
278
|
+
lineCount++;
|
|
279
|
+
return lineCount;
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
await fileHandle.close();
|
|
283
|
+
}
|
|
255
284
|
};
|
|
256
285
|
const handleComparisonOperator = (operator, originalValue, comparedAtValue, fieldType, fieldChildrenType) => {
|
|
257
286
|
if (Array.isArray(fieldType))
|
|
@@ -305,139 +334,155 @@ const handleComparisonOperator = (operator, originalValue, comparedAtValue, fiel
|
|
|
305
334
|
}
|
|
306
335
|
};
|
|
307
336
|
export const search = async (filePath, operator, comparedAtValue, logicalOperator, fieldType, fieldChildrenType, limit, offset, readWholeFile, secretKey) => {
|
|
308
|
-
let RETURN = new Map(), lineCount = 0, foundItems = 0;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
((
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
if (readWholeFile)
|
|
337
|
+
let fileHandle, RETURN = new Map(), lineCount = 0, foundItems = 0;
|
|
338
|
+
try {
|
|
339
|
+
fileHandle = await open(filePath, "r");
|
|
340
|
+
const rl = doesSupportReadLines()
|
|
341
|
+
? fileHandle.readLines()
|
|
342
|
+
: createInterface({
|
|
343
|
+
input: fileHandle.createReadStream(),
|
|
344
|
+
crlfDelay: Infinity,
|
|
345
|
+
});
|
|
346
|
+
for await (const line of rl) {
|
|
347
|
+
lineCount++;
|
|
348
|
+
const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
|
|
349
|
+
if ((Array.isArray(operator) &&
|
|
350
|
+
Array.isArray(comparedAtValue) &&
|
|
351
|
+
((logicalOperator &&
|
|
352
|
+
logicalOperator === "or" &&
|
|
353
|
+
operator.some((single_operator, index) => handleComparisonOperator(single_operator, decodedLine, comparedAtValue[index], fieldType))) ||
|
|
354
|
+
operator.every((single_operator, index) => handleComparisonOperator(single_operator, decodedLine, comparedAtValue[index], fieldType)))) ||
|
|
355
|
+
(!Array.isArray(operator) &&
|
|
356
|
+
handleComparisonOperator(operator, decodedLine, comparedAtValue, fieldType))) {
|
|
357
|
+
foundItems++;
|
|
358
|
+
if (offset && foundItems < offset)
|
|
331
359
|
continue;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
360
|
+
if (limit && foundItems > limit)
|
|
361
|
+
if (readWholeFile)
|
|
362
|
+
continue;
|
|
363
|
+
else
|
|
364
|
+
break;
|
|
365
|
+
RETURN.set(lineCount, decodedLine);
|
|
366
|
+
}
|
|
335
367
|
}
|
|
368
|
+
return foundItems
|
|
369
|
+
? [
|
|
370
|
+
Object.fromEntries(RETURN),
|
|
371
|
+
readWholeFile ? foundItems : foundItems - 1,
|
|
372
|
+
]
|
|
373
|
+
: [null, 0];
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
await fileHandle?.close();
|
|
336
377
|
}
|
|
337
|
-
await fileHandle.close();
|
|
338
|
-
return foundItems
|
|
339
|
-
? [Object.fromEntries(RETURN), readWholeFile ? foundItems : foundItems - 1]
|
|
340
|
-
: [null, 0];
|
|
341
378
|
};
|
|
342
379
|
export const sum = async (filePath, lineNumbers) => {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
380
|
+
let fileHandle, sum = 0;
|
|
381
|
+
try {
|
|
382
|
+
fileHandle = await open(filePath, "r");
|
|
383
|
+
const rl = doesSupportReadLines()
|
|
384
|
+
? fileHandle.readLines()
|
|
385
|
+
: createInterface({
|
|
386
|
+
input: fileHandle.createReadStream(),
|
|
387
|
+
crlfDelay: Infinity,
|
|
388
|
+
});
|
|
389
|
+
if (lineNumbers) {
|
|
390
|
+
let lineCount = 0;
|
|
391
|
+
let lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
392
|
+
for await (const line of rl) {
|
|
393
|
+
lineCount++;
|
|
394
|
+
if (!lineNumbersArray.has(lineCount))
|
|
395
|
+
continue;
|
|
396
|
+
sum += +decode(line, "number");
|
|
397
|
+
lineNumbersArray.delete(lineCount);
|
|
398
|
+
if (!lineNumbersArray.size)
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
361
401
|
}
|
|
402
|
+
else
|
|
403
|
+
for await (const line of rl)
|
|
404
|
+
sum += +decode(line, "number");
|
|
405
|
+
return sum;
|
|
406
|
+
}
|
|
407
|
+
finally {
|
|
408
|
+
await fileHandle?.close();
|
|
362
409
|
}
|
|
363
|
-
else
|
|
364
|
-
for await (const line of rl)
|
|
365
|
-
sum += +decode(line, "number");
|
|
366
|
-
return sum;
|
|
367
410
|
};
|
|
368
411
|
export const max = async (filePath, lineNumbers) => {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
412
|
+
let fileHandle, max = 0;
|
|
413
|
+
try {
|
|
414
|
+
fileHandle = await open(filePath, "r");
|
|
415
|
+
const rl = doesSupportReadLines()
|
|
416
|
+
? fileHandle.readLines()
|
|
417
|
+
: createInterface({
|
|
418
|
+
input: fileHandle.createReadStream(),
|
|
419
|
+
crlfDelay: Infinity,
|
|
420
|
+
});
|
|
421
|
+
if (lineNumbers) {
|
|
422
|
+
let lineCount = 0;
|
|
423
|
+
let lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
424
|
+
for await (const line of rl) {
|
|
425
|
+
lineCount++;
|
|
426
|
+
if (!lineNumbersArray.has(lineCount))
|
|
427
|
+
continue;
|
|
428
|
+
const lineContentNum = +decode(line, "number");
|
|
429
|
+
if (lineContentNum > max)
|
|
430
|
+
max = lineContentNum;
|
|
431
|
+
lineNumbersArray.delete(lineCount);
|
|
432
|
+
if (!lineNumbersArray.size)
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
389
435
|
}
|
|
436
|
+
else
|
|
437
|
+
for await (const line of rl) {
|
|
438
|
+
const lineContentNum = +decode(line, "number");
|
|
439
|
+
if (lineContentNum > max)
|
|
440
|
+
max = lineContentNum;
|
|
441
|
+
}
|
|
442
|
+
return max;
|
|
443
|
+
}
|
|
444
|
+
finally {
|
|
445
|
+
await fileHandle?.close();
|
|
390
446
|
}
|
|
391
|
-
else
|
|
392
|
-
for await (const line of rl) {
|
|
393
|
-
const lineContentNum = +decode(line, "number");
|
|
394
|
-
if (lineContentNum > max)
|
|
395
|
-
max = lineContentNum;
|
|
396
|
-
}
|
|
397
|
-
return max;
|
|
398
447
|
};
|
|
399
448
|
export const min = async (filePath, lineNumbers) => {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
449
|
+
let fileHandle, min = 0;
|
|
450
|
+
try {
|
|
451
|
+
fileHandle = await open(filePath, "r");
|
|
452
|
+
const rl = doesSupportReadLines()
|
|
453
|
+
? fileHandle.readLines()
|
|
454
|
+
: createInterface({
|
|
455
|
+
input: fileHandle.createReadStream(),
|
|
456
|
+
crlfDelay: Infinity,
|
|
457
|
+
});
|
|
458
|
+
if (lineNumbers) {
|
|
459
|
+
let lineCount = 0;
|
|
460
|
+
let lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
461
|
+
for await (const line of rl) {
|
|
462
|
+
lineCount++;
|
|
463
|
+
if (!lineNumbersArray.has(lineCount))
|
|
464
|
+
continue;
|
|
465
|
+
const lineContentNum = +decode(line, "number");
|
|
466
|
+
if (lineContentNum < min)
|
|
467
|
+
min = lineContentNum;
|
|
468
|
+
lineNumbersArray.delete(lineCount);
|
|
469
|
+
if (!lineNumbersArray.size)
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
420
472
|
}
|
|
473
|
+
else
|
|
474
|
+
for await (const line of rl) {
|
|
475
|
+
const lineContentNum = +decode(line, "number");
|
|
476
|
+
if (lineContentNum < min)
|
|
477
|
+
min = lineContentNum;
|
|
478
|
+
}
|
|
479
|
+
return min;
|
|
480
|
+
}
|
|
481
|
+
finally {
|
|
482
|
+
await fileHandle?.close();
|
|
421
483
|
}
|
|
422
|
-
else
|
|
423
|
-
for await (const line of rl) {
|
|
424
|
-
const lineContentNum = +decode(line, "number");
|
|
425
|
-
if (lineContentNum < min)
|
|
426
|
-
min = lineContentNum;
|
|
427
|
-
}
|
|
428
|
-
return min;
|
|
429
|
-
};
|
|
430
|
-
export const sort = async (filePath, sortDirection, lineNumbers, _lineNumbersPerChunk = 100000) => {
|
|
431
|
-
const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
|
|
432
|
-
? fileHandle.readLines({ autoClose: false })
|
|
433
|
-
: createInterface({
|
|
434
|
-
input: fileHandle.createReadStream({ autoClose: false }),
|
|
435
|
-
crlfDelay: Infinity,
|
|
436
|
-
});
|
|
437
|
-
let lineCount = 0;
|
|
438
|
-
for await (const line of rl)
|
|
439
|
-
lineCount++;
|
|
440
484
|
};
|
|
485
|
+
export const sort = async (filePath, sortDirection, lineNumbers, _lineNumbersPerChunk = 100000) => { };
|
|
441
486
|
export default class File {
|
|
442
487
|
static get = get;
|
|
443
488
|
static remove = remove;
|
package/dist/index.d.ts
CHANGED
|
@@ -84,10 +84,13 @@ export default class Inibase {
|
|
|
84
84
|
put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria | undefined, options?: Options | undefined, returnPostedData?: false): Promise<void | null>;
|
|
85
85
|
put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
86
86
|
put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
87
|
-
delete(tableName: string, where?: number | string
|
|
87
|
+
delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<string | null>;
|
|
88
|
+
delete(tableName: string, where?: (number | string)[], _id?: string | string[]): Promise<string[] | null>;
|
|
88
89
|
sum(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
89
90
|
sum(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
90
|
-
max(tableName: string, columns: string
|
|
91
|
-
|
|
91
|
+
max(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
92
|
+
max(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
93
|
+
min(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
|
|
94
|
+
min(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
|
|
92
95
|
}
|
|
93
96
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ export default class Inibase {
|
|
|
74
74
|
return RETURN;
|
|
75
75
|
}, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath(await this.getTableSchema(tableName)), schemaToIdsPath(schema));
|
|
76
76
|
if (replaceOldPathes)
|
|
77
|
-
for (const [oldPath, newPath] of Object.entries(replaceOldPathes))
|
|
77
|
+
for await (const [oldPath, newPath] of Object.entries(replaceOldPathes))
|
|
78
78
|
if (await File.isExists(join(TablePath, oldPath)))
|
|
79
79
|
await rename(join(TablePath, oldPath), join(TablePath, newPath));
|
|
80
80
|
}
|
|
@@ -294,7 +294,7 @@ export default class Inibase {
|
|
|
294
294
|
async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
|
|
295
295
|
const path = join(this.folder, this.database, tableName);
|
|
296
296
|
let RETURN = {};
|
|
297
|
-
for (const field of schema) {
|
|
297
|
+
for await (const field of schema) {
|
|
298
298
|
if ((field.type === "array" ||
|
|
299
299
|
(Array.isArray(field.type) &&
|
|
300
300
|
field.type.includes("array"))) &&
|
|
@@ -382,7 +382,7 @@ export default class Inibase {
|
|
|
382
382
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
383
383
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
|
|
384
384
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
385
|
-
for (const [index, item] of Object.entries(items)) {
|
|
385
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
386
386
|
if (!RETURN[index])
|
|
387
387
|
RETURN[index] = {};
|
|
388
388
|
RETURN[index][field.key] = item
|
|
@@ -401,7 +401,7 @@ export default class Inibase {
|
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
else if (field.type === "object") {
|
|
404
|
-
for (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, (prefix ?? "") + field.key + ".")) ?? {})) {
|
|
404
|
+
for await (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, (prefix ?? "") + field.key + ".")) ?? {})) {
|
|
405
405
|
if (!RETURN[index])
|
|
406
406
|
RETURN[index] = {};
|
|
407
407
|
if (Utils.isObject(item)) {
|
|
@@ -424,7 +424,7 @@ export default class Inibase {
|
|
|
424
424
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
425
425
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
|
|
426
426
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
427
|
-
for (const [index, item] of Object.entries(items)) {
|
|
427
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
428
428
|
if (!RETURN[index])
|
|
429
429
|
RETURN[index] = {};
|
|
430
430
|
RETURN[index][field.key] = item
|
|
@@ -449,8 +449,7 @@ export default class Inibase {
|
|
|
449
449
|
switch (value[0]) {
|
|
450
450
|
case ">":
|
|
451
451
|
case "<":
|
|
452
|
-
|
|
453
|
-
return ["=", "]", "*"].includes(value[1])
|
|
452
|
+
return value[1] === "="
|
|
454
453
|
? [
|
|
455
454
|
value.slice(0, 2),
|
|
456
455
|
value.slice(2),
|
|
@@ -459,6 +458,13 @@ export default class Inibase {
|
|
|
459
458
|
value.slice(0, 1),
|
|
460
459
|
value.slice(1),
|
|
461
460
|
];
|
|
461
|
+
case "[":
|
|
462
|
+
return value[1] === "]"
|
|
463
|
+
? [
|
|
464
|
+
value.slice(0, 2),
|
|
465
|
+
value.slice(2).toString().split(","),
|
|
466
|
+
]
|
|
467
|
+
: ["[]", value.slice(1)];
|
|
462
468
|
case "!":
|
|
463
469
|
return ["=", "*"].includes(value[1])
|
|
464
470
|
? [
|
|
@@ -516,7 +522,7 @@ export default class Inibase {
|
|
|
516
522
|
if (allTrue === undefined)
|
|
517
523
|
allTrue = true;
|
|
518
524
|
let index = -1;
|
|
519
|
-
for (const [key, value] of Object.entries(criteria)) {
|
|
525
|
+
for await (const [key, value] of Object.entries(criteria)) {
|
|
520
526
|
const field = this.getField(key, schema);
|
|
521
527
|
index++;
|
|
522
528
|
let searchOperator = undefined, searchComparedAtValue = undefined, searchLogicalOperator = undefined;
|
|
@@ -696,13 +702,13 @@ export default class Inibase {
|
|
|
696
702
|
RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
|
|
697
703
|
id: ++last_id,
|
|
698
704
|
...rest,
|
|
699
|
-
createdAt:
|
|
705
|
+
createdAt: Date.now(),
|
|
700
706
|
}));
|
|
701
707
|
else
|
|
702
708
|
RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
703
709
|
id: ++last_id,
|
|
704
710
|
...rest,
|
|
705
|
-
createdAt:
|
|
711
|
+
createdAt: Date.now(),
|
|
706
712
|
}))(data);
|
|
707
713
|
if (!RETURN)
|
|
708
714
|
throw this.throwError("NO_DATA");
|
|
@@ -743,11 +749,11 @@ export default class Inibase {
|
|
|
743
749
|
const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), Utils.isArrayOfObjects(data)
|
|
744
750
|
? data.map((item) => ({
|
|
745
751
|
...(({ id, ...restOfData }) => restOfData)(item),
|
|
746
|
-
updatedAt:
|
|
752
|
+
updatedAt: Date.now(),
|
|
747
753
|
}))
|
|
748
754
|
: {
|
|
749
755
|
...(({ id, ...restOfData }) => restOfData)(data),
|
|
750
|
-
updatedAt:
|
|
756
|
+
updatedAt: Date.now(),
|
|
751
757
|
});
|
|
752
758
|
for await (const [path, content] of Object.entries(pathesContents))
|
|
753
759
|
await File.replace(path, content);
|
|
@@ -770,9 +776,9 @@ export default class Inibase {
|
|
|
770
776
|
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(join(this.folder, this.database, tableName), Utils.isArrayOfObjects(data)
|
|
771
777
|
? data.map((item) => ({
|
|
772
778
|
...item,
|
|
773
|
-
updatedAt:
|
|
779
|
+
updatedAt: Date.now(),
|
|
774
780
|
}))
|
|
775
|
-
: { ...data, updatedAt:
|
|
781
|
+
: { ...data, updatedAt: Date.now() })).map(([path, content]) => [
|
|
776
782
|
path,
|
|
777
783
|
[...(Array.isArray(where) ? where : [where])].reduce((obj, lineNum, index) => ({
|
|
778
784
|
...obj,
|
|
@@ -802,11 +808,10 @@ export default class Inibase {
|
|
|
802
808
|
if (!(await File.isExists(idFilePath)))
|
|
803
809
|
throw this.throwError("NO_ITEMS", tableName);
|
|
804
810
|
if (!where) {
|
|
805
|
-
const files = await readdir(join(this.folder, this.database, tableName));
|
|
806
|
-
if (files.length)
|
|
807
|
-
for (const file
|
|
811
|
+
const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
812
|
+
if (files.length)
|
|
813
|
+
for await (const file of files)
|
|
808
814
|
await unlink(join(this.folder, this.database, tableName, file));
|
|
809
|
-
}
|
|
810
815
|
return "*";
|
|
811
816
|
}
|
|
812
817
|
else if ((Array.isArray(where) &&
|
|
@@ -821,13 +826,13 @@ export default class Inibase {
|
|
|
821
826
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
822
827
|
Utils.isNumber(where)) {
|
|
823
828
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
824
|
-
const files = await readdir(join(this.folder, this.database, tableName));
|
|
829
|
+
const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
825
830
|
if (files.length) {
|
|
826
831
|
if (!_id)
|
|
827
832
|
_id = Object.values((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0] ?? {}).map((id) => UtilsServer.encodeID(Number(id), this.salt));
|
|
828
833
|
if (!_id.length)
|
|
829
834
|
throw this.throwError("NO_ITEMS", tableName);
|
|
830
|
-
for (const file of files
|
|
835
|
+
for await (const file of files)
|
|
831
836
|
await File.remove(join(this.folder, this.database, tableName, file), where);
|
|
832
837
|
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
833
838
|
}
|
package/dist/utils.js
CHANGED
|
@@ -7,7 +7,7 @@ export const isObject = (obj) => obj != null &&
|
|
|
7
7
|
export const deepMerge = (target, source) => {
|
|
8
8
|
for (const key in source) {
|
|
9
9
|
if (source.hasOwnProperty(key)) {
|
|
10
|
-
if (source[key]
|
|
10
|
+
if (isObject(source[key]) && isObject(target[key]))
|
|
11
11
|
target[key] = deepMerge(target[key], source[key]);
|
|
12
12
|
else
|
|
13
13
|
target[key] = source[key];
|
package/dist/utils.server.d.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { type Schema } from "./index.js";
|
|
3
3
|
export declare const hashPassword: (password: string) => string;
|
|
4
4
|
export declare const comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
|
|
5
|
-
export declare const encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
|
|
5
|
+
export declare const encodeID: (id: number | string, secretKeyOrSalt: string | number | Buffer) => string;
|
|
6
6
|
export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
|
|
7
7
|
export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
|
|
8
8
|
export declare const addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
|
|
9
9
|
export default class UtilsServer {
|
|
10
|
-
static encodeID: (id: number, secretKeyOrSalt: string | number | Buffer) => string;
|
|
10
|
+
static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
|
|
11
11
|
static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
|
|
12
12
|
static hashPassword: (password: string) => string;
|
|
13
13
|
static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
|