inibase 1.0.0-rc.60 → 1.0.0-rc.61
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 +111 -78
- package/dist/file.d.ts +3 -3
- package/dist/file.js +42 -44
- package/dist/index.d.ts +20 -11
- package/dist/index.js +206 -156
- package/dist/utils.d.ts +1 -3
- package/dist/utils.js +37 -1
- package/dist/utils.server.d.ts +5 -0
- package/dist/utils.server.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,44 +64,6 @@ const users = await db.get("user", { favoriteFoods: "![]Pizza,Burger" });
|
|
|
64
64
|
|
|
65
65
|
This structure ensures efficient storage, retrieval, and updates, making our system scalable and high-performing for diverse datasets and applications.
|
|
66
66
|
|
|
67
|
-
## Config (.env)
|
|
68
|
-
|
|
69
|
-
The `.env` file supports the following parameters
|
|
70
|
-
|
|
71
|
-
```ini
|
|
72
|
-
# Don't add this line, it's an auto generated secret key, will be using for encrypting the IDs
|
|
73
|
-
INIBASE_SECRET=
|
|
74
|
-
|
|
75
|
-
INIBASE_COMPRESSION=false
|
|
76
|
-
INIBASE_CACHE=false
|
|
77
|
-
|
|
78
|
-
# Prepend new items to the beginning of file
|
|
79
|
-
INIBASE_REVERSE=false
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Benchmark
|
|
83
|
-
|
|
84
|
-
### Bulk
|
|
85
|
-
|
|
86
|
-
| | 10 | 100 | 1000 |
|
|
87
|
-
|--------|-----------------|-----------------|-----------------|
|
|
88
|
-
| POST | 11 ms (0.65 mb) | 19 ms (1.00 mb) | 85 ms (4.58 mb) |
|
|
89
|
-
| GET | 14 ms (2.77 mb) | 12 ms (3.16 mb) | 34 ms (1.38 mb) |
|
|
90
|
-
| PUT | 6 ms (1.11 mb) | 5 ms (1.37 mb) | 10 ms (1.12 mb) |
|
|
91
|
-
| DELETE | 17 ms (1.68 mb) | 14 ms (5.45 mb) | 25 ms (5.94 mb) |
|
|
92
|
-
|
|
93
|
-
### Single
|
|
94
|
-
|
|
95
|
-
| | 10 | 100 | 1000 |
|
|
96
|
-
|--------|-------------------|--------------------|--------------------|
|
|
97
|
-
| POST | 43 ms (4.70 mb) | 387 ms (6.36 mb) | 5341 ms (24.73 mb) |
|
|
98
|
-
| GET | 99 ms (12.51 mb) | 846 ms (30.68 mb) | 7103 ms (30.86 mb) |
|
|
99
|
-
| PUT | 33 ms (10.29 mb) | 312 ms (11.06 mb) | 3539 ms (14.87 mb) |
|
|
100
|
-
| DELETE | 134 ms (13.50 mb) | 1224 ms (16.57 mb) | 7339 ms (11.46 mb) |
|
|
101
|
-
|
|
102
|
-
> Testing by default with `user` table, with username, email, password fields _so results include password encryption process_ <br>
|
|
103
|
-
> To run benchmarks, install *typescript* & *tsx* globally and run `benchmark` `benchmark:bulk` `benchmark:single`
|
|
104
|
-
|
|
105
67
|
## Inibase CLI
|
|
106
68
|
|
|
107
69
|
```shell
|
|
@@ -145,48 +107,75 @@ delete <tableName> -w <ID|LineNumber|Criteria>
|
|
|
145
107
|
## Examples
|
|
146
108
|
|
|
147
109
|
<details>
|
|
148
|
-
<summary>
|
|
110
|
+
<summary>Tables</summary>
|
|
149
111
|
<blockquote>
|
|
150
112
|
|
|
151
113
|
<details>
|
|
152
|
-
<summary>
|
|
114
|
+
<summary>Config</summary>
|
|
153
115
|
<blockquote>
|
|
154
116
|
|
|
117
|
+
```ts
|
|
118
|
+
interface {
|
|
119
|
+
compression: boolean;
|
|
120
|
+
cache: boolean;
|
|
121
|
+
prepend: boolean;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
</blockquote>
|
|
125
|
+
</details>
|
|
126
|
+
|
|
155
127
|
<details>
|
|
156
|
-
<summary>
|
|
128
|
+
<summary>Schema</summary>
|
|
157
129
|
<blockquote>
|
|
158
|
-
Inside the table folder
|
|
159
130
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
131
|
+
```ts
|
|
132
|
+
interface {
|
|
133
|
+
id: number; // stored as a Number but displayed as a hashed ID
|
|
134
|
+
key: string;
|
|
135
|
+
required?: boolean;
|
|
136
|
+
unique?: boolean;
|
|
137
|
+
type: "string" | "number" | "boolean" | "date" | "email" | "url" | "password" | "html" | "ip" | "json" | "id";
|
|
138
|
+
}
|
|
139
|
+
interface Table {
|
|
140
|
+
id: number;
|
|
141
|
+
key: string;
|
|
142
|
+
required?: boolean;
|
|
143
|
+
type: "table";
|
|
144
|
+
table: string;
|
|
145
|
+
}
|
|
146
|
+
interface Array {
|
|
147
|
+
id: number;
|
|
148
|
+
key: string;
|
|
149
|
+
required?: boolean;
|
|
150
|
+
type: "array";
|
|
151
|
+
children: string|string[];
|
|
152
|
+
}
|
|
153
|
+
interface ObjectOrArrayOfObjects {
|
|
154
|
+
id: number;
|
|
155
|
+
key: string;
|
|
156
|
+
required?: boolean;
|
|
157
|
+
type: "object" | "array";
|
|
158
|
+
children: Schema;
|
|
159
|
+
}
|
|
177
160
|
```
|
|
178
161
|
</blockquote>
|
|
179
162
|
</details>
|
|
180
163
|
|
|
181
164
|
<details>
|
|
182
|
-
<summary>
|
|
165
|
+
<summary>Create Table</summary>
|
|
183
166
|
<blockquote>
|
|
184
167
|
|
|
185
168
|
```js
|
|
186
169
|
import Inibase from "inibase";
|
|
187
170
|
const db = new Inibase("/databaseName");
|
|
188
171
|
|
|
189
|
-
const
|
|
172
|
+
const userTableConfig = {
|
|
173
|
+
compression: true,
|
|
174
|
+
cache: true,
|
|
175
|
+
prepend: false
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const userTableSchema = [
|
|
190
179
|
{
|
|
191
180
|
key: "username",
|
|
192
181
|
type: "string",
|
|
@@ -252,14 +241,15 @@ const userSchema = [
|
|
|
252
241
|
},
|
|
253
242
|
];
|
|
254
243
|
|
|
255
|
-
await db.
|
|
244
|
+
await db.createTable("user", userTableSchema, userTableConfig);
|
|
256
245
|
```
|
|
257
246
|
</blockquote>
|
|
258
247
|
</details>
|
|
259
248
|
|
|
260
|
-
|
|
261
|
-
</
|
|
262
|
-
|
|
249
|
+
<details>
|
|
250
|
+
<summary>Update Table</summary>
|
|
251
|
+
<blockquote>
|
|
252
|
+
|
|
263
253
|
<details>
|
|
264
254
|
<summary>Add field</summary>
|
|
265
255
|
<blockquote>
|
|
@@ -268,10 +258,10 @@ await db.setTableSchema("user", userSchema);
|
|
|
268
258
|
import Inibase from "inibase";
|
|
269
259
|
const db = new Inibase("/databaseName");
|
|
270
260
|
|
|
271
|
-
const
|
|
272
|
-
const
|
|
261
|
+
const userTableSchema = (await db.getTable("user")).schema;
|
|
262
|
+
const newUserTableSchema = [...userTableSchema, {key: "phone2", type: "number", required: false}];
|
|
273
263
|
|
|
274
|
-
await db.
|
|
264
|
+
await db.updateTable("user", newUserTableSchema);
|
|
275
265
|
```
|
|
276
266
|
</blockquote>
|
|
277
267
|
</details>
|
|
@@ -286,13 +276,33 @@ import { setField } from "inibase/utils";
|
|
|
286
276
|
|
|
287
277
|
const db = new Inibase("/databaseName");
|
|
288
278
|
|
|
289
|
-
const
|
|
290
|
-
setField("username",
|
|
291
|
-
await db.
|
|
279
|
+
const userTableSchema = (await db.getTable("user")).schema;
|
|
280
|
+
setField("username", userTableSchema, {key: "fullName"});
|
|
281
|
+
await db.updateTable("user", newUserTableSchema);
|
|
292
282
|
```
|
|
293
283
|
</blockquote>
|
|
294
284
|
</details>
|
|
295
285
|
|
|
286
|
+
<details>
|
|
287
|
+
<summary>Remove field</summary>
|
|
288
|
+
<blockquote>
|
|
289
|
+
|
|
290
|
+
```js
|
|
291
|
+
import Inibase from "inibase";
|
|
292
|
+
import { unsetField } from "inibase/utils";
|
|
293
|
+
|
|
294
|
+
const db = new Inibase("/databaseName");
|
|
295
|
+
|
|
296
|
+
const userTableSchema = (await db.getTable("user")).schema;
|
|
297
|
+
unsetField("fullName", userTableSchema);
|
|
298
|
+
await db.updateTable("user", newUserTableSchema);
|
|
299
|
+
```
|
|
300
|
+
</blockquote>
|
|
301
|
+
</details>
|
|
302
|
+
|
|
303
|
+
</blockquote>
|
|
304
|
+
</details>
|
|
305
|
+
|
|
296
306
|
<details>
|
|
297
307
|
<summary>Join Tables</summary>
|
|
298
308
|
<blockquote>
|
|
@@ -301,7 +311,7 @@ await db.setTableSchema("user", newUserSchema);
|
|
|
301
311
|
import Inibase from "inibase";
|
|
302
312
|
const db = new Inibase("/databaseName");
|
|
303
313
|
|
|
304
|
-
const
|
|
314
|
+
const productTableSchema = [
|
|
305
315
|
{
|
|
306
316
|
key: "title",
|
|
307
317
|
type: "string",
|
|
@@ -319,9 +329,9 @@ const productSchema = [
|
|
|
319
329
|
},
|
|
320
330
|
];
|
|
321
331
|
|
|
322
|
-
await db.
|
|
332
|
+
await db.createTable("product", productTableSchema);
|
|
323
333
|
|
|
324
|
-
const
|
|
334
|
+
const productTableData = [
|
|
325
335
|
{
|
|
326
336
|
title: "Product 1",
|
|
327
337
|
price: 16,
|
|
@@ -334,7 +344,7 @@ const productData = [
|
|
|
334
344
|
},
|
|
335
345
|
];
|
|
336
346
|
|
|
337
|
-
const product = await db.post("product",
|
|
347
|
+
const product = await db.post("product", productTableData);
|
|
338
348
|
// [
|
|
339
349
|
// {
|
|
340
350
|
// "id": "1d88385d4b1581f8fb059334dec30f4c",
|
|
@@ -373,7 +383,7 @@ const product = await db.post("product", productData);
|
|
|
373
383
|
import Inibase from "inibase";
|
|
374
384
|
const db = new Inibase("/databaseName");
|
|
375
385
|
|
|
376
|
-
const
|
|
386
|
+
const userTableData = [
|
|
377
387
|
{
|
|
378
388
|
username: "user1",
|
|
379
389
|
email: "user1@example.com",
|
|
@@ -408,7 +418,7 @@ const userData = [
|
|
|
408
418
|
},
|
|
409
419
|
];
|
|
410
420
|
|
|
411
|
-
const users = await db.post("user",
|
|
421
|
+
const users = await db.post("user", userTableData);
|
|
412
422
|
// [
|
|
413
423
|
// {
|
|
414
424
|
// "id": "1d88385d4b1581f8fb059334dec30f4c",
|
|
@@ -664,6 +674,29 @@ await db.sort("user", {age: -1, username: "asc"});
|
|
|
664
674
|
</blockquote>
|
|
665
675
|
</details>
|
|
666
676
|
|
|
677
|
+
## Benchmark
|
|
678
|
+
|
|
679
|
+
### Bulk
|
|
680
|
+
|
|
681
|
+
| | 10 | 100 | 1000 |
|
|
682
|
+
|--------|-----------------|-----------------|-----------------|
|
|
683
|
+
| POST | 11 ms (0.65 mb) | 19 ms (1.00 mb) | 85 ms (4.58 mb) |
|
|
684
|
+
| GET | 14 ms (2.77 mb) | 12 ms (3.16 mb) | 34 ms (1.38 mb) |
|
|
685
|
+
| PUT | 6 ms (1.11 mb) | 5 ms (1.37 mb) | 10 ms (1.12 mb) |
|
|
686
|
+
| DELETE | 17 ms (1.68 mb) | 14 ms (5.45 mb) | 25 ms (5.94 mb) |
|
|
687
|
+
|
|
688
|
+
### Single
|
|
689
|
+
|
|
690
|
+
| | 10 | 100 | 1000 |
|
|
691
|
+
|--------|-------------------|--------------------|--------------------|
|
|
692
|
+
| POST | 43 ms (4.70 mb) | 387 ms (6.36 mb) | 5341 ms (24.73 mb) |
|
|
693
|
+
| GET | 99 ms (12.51 mb) | 846 ms (30.68 mb) | 7103 ms (30.86 mb) |
|
|
694
|
+
| PUT | 33 ms (10.29 mb) | 312 ms (11.06 mb) | 3539 ms (14.87 mb) |
|
|
695
|
+
| DELETE | 134 ms (13.50 mb) | 1224 ms (16.57 mb) | 7339 ms (11.46 mb) |
|
|
696
|
+
|
|
697
|
+
> Testing by default with `user` table, with username, email, password fields _so results include password encryption process_ <br>
|
|
698
|
+
> To run benchmarks, install *typescript* & *[tsx](https://github.com/privatenumber/tsx)* globally and run `benchmark` `benchmark:bulk` `benchmark:single`
|
|
699
|
+
|
|
667
700
|
## Roadmap
|
|
668
701
|
|
|
669
702
|
- [x] Actions:
|
|
@@ -671,7 +704,7 @@ await db.sort("user", {age: -1, username: "asc"});
|
|
|
671
704
|
- [x] Pagination
|
|
672
705
|
- [x] Criteria
|
|
673
706
|
- [x] Columns
|
|
674
|
-
- [x] Sort
|
|
707
|
+
- [x] Sort
|
|
675
708
|
- [x] POST
|
|
676
709
|
- [x] PUT
|
|
677
710
|
- [x] DELETE
|
package/dist/file.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import type { ComparisonOperator, FieldType, Schema } from "./index.js";
|
|
3
3
|
export declare const lock: (folderPath: string, prefix?: string) => Promise<void>;
|
|
4
4
|
export declare const unlock: (folderPath: string, prefix?: string) => Promise<void>;
|
|
5
|
-
export declare const write: (filePath: string, data: any
|
|
6
|
-
export declare const read: (filePath: string
|
|
5
|
+
export declare const write: (filePath: string, data: any) => Promise<void>;
|
|
6
|
+
export declare const read: (filePath: string) => Promise<string>;
|
|
7
7
|
/**
|
|
8
8
|
* Checks if a file or directory exists at the specified path.
|
|
9
9
|
*
|
|
@@ -68,7 +68,7 @@ export declare const replace: (filePath: string, replacements: string | number |
|
|
|
68
68
|
* @returns Promise<string[]>. Modifies the file by appending data.
|
|
69
69
|
*
|
|
70
70
|
*/
|
|
71
|
-
export declare const append: (filePath: string, data: string | number | (string | number)[]) => Promise<string[]>;
|
|
71
|
+
export declare const append: (filePath: string, data: string | number | (string | number)[], prepend?: boolean) => Promise<string[]>;
|
|
72
72
|
/**
|
|
73
73
|
* Asynchronously removes specified lines from a file.
|
|
74
74
|
*
|
package/dist/file.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { open, access, writeFile, readFile, constants as fsConstants, unlink, copyFile, appendFile,
|
|
1
|
+
import { open, access, writeFile, readFile, constants as fsConstants, unlink, copyFile, appendFile, } from "node:fs/promises";
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { Transform } from "node:stream";
|
|
4
4
|
import { pipeline } from "node:stream/promises";
|
|
5
|
-
import { createGzip, createGunzip
|
|
6
|
-
import {
|
|
7
|
-
import { detectFieldType, isArrayOfObjects, isJSON, isNumber, isObject, } from "./utils.js";
|
|
8
|
-
import { encodeID, compare, exec } from "./utils.server.js";
|
|
9
|
-
import * as Config from "./config.js";
|
|
5
|
+
import { createGzip, createGunzip } from "node:zlib";
|
|
6
|
+
import { join } from "node:path";
|
|
10
7
|
import Inison from "inison";
|
|
8
|
+
import { detectFieldType, isArrayOfObjects, isJSON, isNumber, isObject, } from "./utils.js";
|
|
9
|
+
import { encodeID, compare, exec, gzip, gunzip } from "./utils.server.js";
|
|
11
10
|
export const lock = async (folderPath, prefix) => {
|
|
12
11
|
let lockFile = null;
|
|
13
12
|
const lockFilePath = join(folderPath, `${prefix ?? ""}.locked`);
|
|
@@ -29,17 +28,14 @@ export const unlock = async (folderPath, prefix) => {
|
|
|
29
28
|
}
|
|
30
29
|
catch { }
|
|
31
30
|
};
|
|
32
|
-
export const write = async (filePath, data
|
|
33
|
-
await
|
|
34
|
-
await writeFile(filePath, Config.isCompressionEnabled && !disableCompression
|
|
35
|
-
? gzipSync(String(data))
|
|
36
|
-
: String(data));
|
|
31
|
+
export const write = async (filePath, data) => {
|
|
32
|
+
await writeFile(filePath, filePath.endsWith(".gz") ? await gzip(data) : data);
|
|
37
33
|
};
|
|
38
|
-
export const read = async (filePath
|
|
39
|
-
?
|
|
40
|
-
:
|
|
41
|
-
const _pipeline = async (rl, writeStream, transform) => {
|
|
42
|
-
if (
|
|
34
|
+
export const read = async (filePath) => filePath.endsWith(".gz")
|
|
35
|
+
? (await gunzip(await readFile(filePath, "utf8"))).toString()
|
|
36
|
+
: await readFile(filePath, "utf8");
|
|
37
|
+
const _pipeline = async (filePath, rl, writeStream, transform) => {
|
|
38
|
+
if (filePath.endsWith(".gz"))
|
|
43
39
|
await pipeline(rl, transform, createGzip(), writeStream);
|
|
44
40
|
else
|
|
45
41
|
await pipeline(rl, transform, writeStream);
|
|
@@ -50,8 +46,8 @@ const _pipeline = async (rl, writeStream, transform) => {
|
|
|
50
46
|
* @param fileHandle - The file handle from which to create a read stream.
|
|
51
47
|
* @returns A readline.Interface instance configured with the provided file stream.
|
|
52
48
|
*/
|
|
53
|
-
const
|
|
54
|
-
input:
|
|
49
|
+
const createReadLineInternface = (filePath, fileHandle) => createInterface({
|
|
50
|
+
input: filePath.endsWith(".gz")
|
|
55
51
|
? fileHandle.createReadStream().pipe(createGunzip())
|
|
56
52
|
: fileHandle.createReadStream(),
|
|
57
53
|
crlfDelay: Number.POSITIVE_INFINITY,
|
|
@@ -185,7 +181,7 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
185
181
|
let rl = null;
|
|
186
182
|
try {
|
|
187
183
|
fileHandle = await open(filePath, "r");
|
|
188
|
-
rl =
|
|
184
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
189
185
|
const lines = {};
|
|
190
186
|
let linesCount = 0;
|
|
191
187
|
if (!lineNumbers) {
|
|
@@ -194,17 +190,17 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
194
190
|
lines[linesCount] = decode(line, fieldType, fieldChildrenType, secretKey);
|
|
195
191
|
}
|
|
196
192
|
}
|
|
197
|
-
else if (lineNumbers
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (lastLine)
|
|
204
|
-
lines[linesCount] = decode(lastLine, fieldType, fieldChildrenType, secretKey);
|
|
193
|
+
else if (lineNumbers == -1) {
|
|
194
|
+
const command = filePath.endsWith(".gz")
|
|
195
|
+
? `zcat ${filePath} | sed -n '$p'`
|
|
196
|
+
: `sed -n '$p' ${filePath}`, foundedLine = (await exec(command)).stdout.trim();
|
|
197
|
+
if (foundedLine)
|
|
198
|
+
lines[linesCount] = decode(foundedLine, fieldType, fieldChildrenType, secretKey);
|
|
205
199
|
}
|
|
206
200
|
else {
|
|
207
201
|
lineNumbers = Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers];
|
|
202
|
+
if (lineNumbers.some(Number.isNaN))
|
|
203
|
+
throw new Error("UNVALID_LINE_NUMBERS");
|
|
208
204
|
if (readWholeFile) {
|
|
209
205
|
const lineNumbersArray = new Set(lineNumbers);
|
|
210
206
|
for await (const line of rl) {
|
|
@@ -216,9 +212,9 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
216
212
|
}
|
|
217
213
|
return [lines, linesCount];
|
|
218
214
|
}
|
|
219
|
-
const command =
|
|
215
|
+
const command = filePath.endsWith(".gz")
|
|
220
216
|
? `zcat ${filePath} | sed -n '${lineNumbers.join("p;")}p'`
|
|
221
|
-
: `sed -n '${lineNumbers.join("p;")}p' ${filePath}`, foundedLines = (await exec(command)).stdout.trim().split(
|
|
217
|
+
: `sed -n '${lineNumbers.join("p;")}p' ${filePath}`, foundedLines = (await exec(command)).stdout.trim().split("\n");
|
|
222
218
|
let index = 0;
|
|
223
219
|
for (const line of foundedLines) {
|
|
224
220
|
lines[lineNumbers[index]] = decode(line, fieldType, fieldChildrenType, secretKey);
|
|
@@ -253,8 +249,8 @@ export const replace = async (filePath, replacements) => {
|
|
|
253
249
|
let linesCount = 0;
|
|
254
250
|
fileHandle = await open(filePath, "r");
|
|
255
251
|
fileTempHandle = await open(fileTempPath, "w");
|
|
256
|
-
rl =
|
|
257
|
-
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
252
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
253
|
+
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
258
254
|
transform(line, encoding, callback) {
|
|
259
255
|
linesCount++;
|
|
260
256
|
const replacement = isObject(replacements)
|
|
@@ -297,10 +293,10 @@ export const replace = async (filePath, replacements) => {
|
|
|
297
293
|
* @returns Promise<string[]>. Modifies the file by appending data.
|
|
298
294
|
*
|
|
299
295
|
*/
|
|
300
|
-
export const append = async (filePath, data) => {
|
|
296
|
+
export const append = async (filePath, data, prepend) => {
|
|
301
297
|
const fileTempPath = filePath.replace(/([^/]+)\/?$/, ".tmp/$1");
|
|
302
298
|
if (await isExists(filePath)) {
|
|
303
|
-
if (!
|
|
299
|
+
if (!prepend && !filePath.endsWith(".gz")) {
|
|
304
300
|
await copyFile(filePath, fileTempPath);
|
|
305
301
|
await appendFile(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n`);
|
|
306
302
|
}
|
|
@@ -311,9 +307,9 @@ export const append = async (filePath, data) => {
|
|
|
311
307
|
try {
|
|
312
308
|
fileHandle = await open(filePath, "r");
|
|
313
309
|
fileTempHandle = await open(fileTempPath, "w");
|
|
314
|
-
rl =
|
|
310
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
315
311
|
let isAppended = false;
|
|
316
|
-
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
312
|
+
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
317
313
|
transform(line, _, callback) {
|
|
318
314
|
if (!isAppended) {
|
|
319
315
|
isAppended = true;
|
|
@@ -332,7 +328,7 @@ export const append = async (filePath, data) => {
|
|
|
332
328
|
}
|
|
333
329
|
}
|
|
334
330
|
else
|
|
335
|
-
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n
|
|
331
|
+
await write(fileTempPath, `${Array.isArray(data) ? data.join("\n") : data}\n`);
|
|
336
332
|
return [fileTempPath, filePath];
|
|
337
333
|
};
|
|
338
334
|
/**
|
|
@@ -348,9 +344,11 @@ export const remove = async (filePath, linesToDelete) => {
|
|
|
348
344
|
linesToDelete = Array.isArray(linesToDelete)
|
|
349
345
|
? linesToDelete.map(Number)
|
|
350
346
|
: [Number(linesToDelete)];
|
|
347
|
+
if (linesToDelete.some(Number.isNaN))
|
|
348
|
+
throw new Error("UNVALID_LINE_NUMBERS");
|
|
351
349
|
const fileTempPath = filePath.replace(/([^/]+)\/?$/, ".tmp/$1");
|
|
352
350
|
if (linesToDelete.length < 1000) {
|
|
353
|
-
const command =
|
|
351
|
+
const command = filePath.endsWith(".gz")
|
|
354
352
|
? `zcat ${filePath} | sed "${linesToDelete.join("d;")}d" | gzip > ${fileTempPath}`
|
|
355
353
|
: `sed "${linesToDelete.join("d;")}d" ${filePath} > ${fileTempPath}`;
|
|
356
354
|
await exec(command);
|
|
@@ -361,8 +359,8 @@ export const remove = async (filePath, linesToDelete) => {
|
|
|
361
359
|
const fileHandle = await open(filePath, "r");
|
|
362
360
|
const fileTempHandle = await open(fileTempPath, "w");
|
|
363
361
|
const linesToDeleteArray = new Set(linesToDelete);
|
|
364
|
-
const rl =
|
|
365
|
-
await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
|
|
362
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
363
|
+
await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
|
|
366
364
|
transform(line, _, callback) {
|
|
367
365
|
linesCount++;
|
|
368
366
|
if (linesToDeleteArray.has(linesCount)) {
|
|
@@ -414,7 +412,7 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
414
412
|
// Open the file for reading.
|
|
415
413
|
fileHandle = await open(filePath, "r");
|
|
416
414
|
// Create a Readline interface to read the file line by line.
|
|
417
|
-
rl =
|
|
415
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
418
416
|
// Iterate through each line in the file.
|
|
419
417
|
for await (const line of rl) {
|
|
420
418
|
// Increment the line count for each line.
|
|
@@ -474,7 +472,7 @@ export const count = async (filePath) => {
|
|
|
474
472
|
let rl = null;
|
|
475
473
|
try {
|
|
476
474
|
fileHandle = await open(filePath, "r");
|
|
477
|
-
rl =
|
|
475
|
+
rl = createReadLineInternface(filePath, fileHandle);
|
|
478
476
|
for await (const _ of rl)
|
|
479
477
|
linesCount++;
|
|
480
478
|
}
|
|
@@ -497,7 +495,7 @@ export const count = async (filePath) => {
|
|
|
497
495
|
export const sum = async (filePath, lineNumbers) => {
|
|
498
496
|
let sum = 0;
|
|
499
497
|
const fileHandle = await open(filePath, "r");
|
|
500
|
-
const rl =
|
|
498
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
501
499
|
if (lineNumbers) {
|
|
502
500
|
let linesCount = 0;
|
|
503
501
|
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
@@ -529,7 +527,7 @@ export const sum = async (filePath, lineNumbers) => {
|
|
|
529
527
|
export const max = async (filePath, lineNumbers) => {
|
|
530
528
|
let max = 0;
|
|
531
529
|
const fileHandle = await open(filePath, "r");
|
|
532
|
-
const rl =
|
|
530
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
533
531
|
if (lineNumbers) {
|
|
534
532
|
let linesCount = 0;
|
|
535
533
|
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
|
@@ -566,7 +564,7 @@ export const max = async (filePath, lineNumbers) => {
|
|
|
566
564
|
export const min = async (filePath, lineNumbers) => {
|
|
567
565
|
let min = 0;
|
|
568
566
|
const fileHandle = await open(filePath, "r");
|
|
569
|
-
const rl =
|
|
567
|
+
const rl = createReadLineInternface(filePath, fileHandle);
|
|
570
568
|
if (lineNumbers) {
|
|
571
569
|
let linesCount = 0;
|
|
572
570
|
const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,15 @@ export interface Options {
|
|
|
23
23
|
columns?: string[] | string;
|
|
24
24
|
order?: Record<string, "asc" | "desc">;
|
|
25
25
|
}
|
|
26
|
+
export interface Config {
|
|
27
|
+
compression: boolean;
|
|
28
|
+
cache: boolean;
|
|
29
|
+
prepend: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface TableObject {
|
|
32
|
+
schema?: Schema;
|
|
33
|
+
config: Config;
|
|
34
|
+
}
|
|
26
35
|
export type ComparisonOperator = "=" | "!=" | ">" | "<" | ">=" | "<=" | "*" | "!*" | "[]" | "![]";
|
|
27
36
|
type pageInfo = {
|
|
28
37
|
total?: number;
|
|
@@ -41,24 +50,25 @@ declare global {
|
|
|
41
50
|
entries<T extends object>(o: T): Entries<T>;
|
|
42
51
|
}
|
|
43
52
|
}
|
|
44
|
-
export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "NO_ITEMS" | "NO_RESULTS" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV";
|
|
53
|
+
export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "NO_ITEMS" | "NO_RESULTS" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS";
|
|
45
54
|
export type ErrorLang = "en";
|
|
46
55
|
export default class Inibase {
|
|
47
|
-
folder: string;
|
|
48
|
-
database: string;
|
|
49
|
-
table: string | null;
|
|
50
56
|
pageInfo: Record<string, pageInfo>;
|
|
57
|
+
salt: Buffer;
|
|
58
|
+
private databasePath;
|
|
59
|
+
private tables;
|
|
51
60
|
private fileExtension;
|
|
52
61
|
private checkIFunique;
|
|
53
62
|
private totalItems;
|
|
54
|
-
|
|
55
|
-
constructor(database: string, mainFolder?: string, _table?: string | null, _totalItems?: Record<string, number>, _pageInfo?: Record<string, pageInfo>, _isThreadEnabled?: boolean);
|
|
63
|
+
constructor(database: string, mainFolder?: string);
|
|
56
64
|
private throwError;
|
|
57
65
|
private getFileExtension;
|
|
58
66
|
private _schemaToIdsPath;
|
|
59
|
-
|
|
67
|
+
createTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
|
|
68
|
+
updateTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
|
|
69
|
+
getTable(tableName: string): Promise<TableObject>;
|
|
60
70
|
getTableSchema(tableName: string, encodeIDs?: boolean): Promise<Schema | undefined>;
|
|
61
|
-
private
|
|
71
|
+
private throwErrorIfTableEmpty;
|
|
62
72
|
private validateData;
|
|
63
73
|
private formatField;
|
|
64
74
|
private checkUnique;
|
|
@@ -66,15 +76,14 @@ export default class Inibase {
|
|
|
66
76
|
private getDefaultValue;
|
|
67
77
|
private _combineObjectsToArray;
|
|
68
78
|
private _CombineData;
|
|
69
|
-
private _addPathToKeys;
|
|
70
79
|
private joinPathesContents;
|
|
71
80
|
private _getItemsFromSchemaHelper;
|
|
72
81
|
private getItemsFromSchema;
|
|
73
82
|
private applyCriteria;
|
|
74
83
|
private _filterSchemaByColumns;
|
|
75
84
|
clearCache(tablePath: string): Promise<void>;
|
|
76
|
-
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined,
|
|
77
|
-
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true,
|
|
85
|
+
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, _skipIdColumn?: boolean): Promise<Data | null>;
|
|
86
|
+
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, _skipIdColumn?: boolean): Promise<number[]>;
|
|
78
87
|
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
|
|
79
88
|
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
80
89
|
post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|