inibase 1.0.0-rc.4 → 1.0.0-rc.6
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 +17 -11
- package/file.ts +230 -84
- package/index.test.ts +204 -0
- package/index.ts +715 -417
- package/package.json +4 -3
- package/tsconfig.json +2 -1
- package/utils.ts +156 -45
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Inibase :pencil:
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.org/package/inibase) [](https://www.npmjs.org/package/inibase) [](./LICENSE) [](https://github.com/inicontent/inibase/pulse) [](https://github.com/inicontent/inibase)
|
|
6
6
|
|
|
7
7
|
> File-based relational database, simple to use and can handle large data :fire:
|
|
8
8
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
```js
|
|
23
23
|
import Inibase from "inibase";
|
|
24
|
-
const db = new Inibase("
|
|
24
|
+
const db = new Inibase("database_name");
|
|
25
25
|
|
|
26
26
|
// Get all items from "user" table
|
|
27
27
|
const users = await db.get("user");
|
|
@@ -30,12 +30,12 @@ const users = await db.get("user");
|
|
|
30
30
|
const users = await db.get("user", undefined, { page: 2, per_page: 15 });
|
|
31
31
|
|
|
32
32
|
// Get only required columns to improve speed
|
|
33
|
-
const users = await
|
|
33
|
+
const users = await db.get("user", undefined, {
|
|
34
34
|
columns: ["username", "address.street", "hobbies.*.name"],
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
// Get items from "user" table where "favoriteFoods" does not includes "Pizza"
|
|
38
|
-
const users = await
|
|
38
|
+
const users = await db.get("user", { favoriteFoods: "![]Pizza" });
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
If you like Inibase, please sponsor: [GitHub Sponsors](https://github.com/sponsors/inicontent) || [Paypal](https://paypal.me/KarimAmahtil).
|
|
@@ -50,11 +50,7 @@ Become a sponsor and have your company logo here 👉 [GitHub Sponsors](https://
|
|
|
50
50
|
## Install
|
|
51
51
|
|
|
52
52
|
```js
|
|
53
|
-
|
|
54
|
-
npm install inibase
|
|
55
|
-
|
|
56
|
-
// pnpm
|
|
57
|
-
pnpm add inibase
|
|
53
|
+
<npm|pnpm> install inibase
|
|
58
54
|
```
|
|
59
55
|
|
|
60
56
|
## How it works?
|
|
@@ -342,6 +338,11 @@ const users = await db.get("user", { favoriteFoods: "[]Pizza" });
|
|
|
342
338
|
// },
|
|
343
339
|
// ...
|
|
344
340
|
// ]
|
|
341
|
+
|
|
342
|
+
// Get all "user" columns except "username" & "address.street"
|
|
343
|
+
const users = await db.get("user", undefined, {
|
|
344
|
+
columns: ["!username", "!address.street"],
|
|
345
|
+
});
|
|
345
346
|
```
|
|
346
347
|
|
|
347
348
|
</details>
|
|
@@ -445,7 +446,7 @@ type Data = {
|
|
|
445
446
|
- [x] Pagination
|
|
446
447
|
- [x] Criteria
|
|
447
448
|
- [x] Columns
|
|
448
|
-
- [ ] Order
|
|
449
|
+
- [ ] Order By
|
|
449
450
|
- [x] POST
|
|
450
451
|
- [x] PUT
|
|
451
452
|
- [x] DELETE
|
|
@@ -460,7 +461,12 @@ type Data = {
|
|
|
460
461
|
- [x] Object
|
|
461
462
|
- [x] Array
|
|
462
463
|
- [x] Password
|
|
463
|
-
- [
|
|
464
|
+
- [x] IP
|
|
465
|
+
- [x] HTML
|
|
466
|
+
- [x] Id
|
|
467
|
+
- [ ] TO-DO:
|
|
468
|
+
- [ ] Improve caching
|
|
469
|
+
- [ ] Commenting the code
|
|
464
470
|
- [ ] Features:
|
|
465
471
|
- [ ] Encryption
|
|
466
472
|
- [ ] Compress data
|
package/file.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import { createWriteStream,
|
|
2
|
-
import { open } from "fs/promises";
|
|
3
|
-
import {
|
|
1
|
+
import { createWriteStream, createReadStream, WriteStream } from "node:fs";
|
|
2
|
+
import { open, unlink, rename, stat } from "node:fs/promises";
|
|
3
|
+
import { Interface, createInterface } from "node:readline";
|
|
4
|
+
import { parse } from "node:path";
|
|
4
5
|
import { ComparisonOperator, FieldType } from ".";
|
|
5
6
|
import Utils from "./utils";
|
|
6
7
|
|
|
8
|
+
const doesSupportReadLines = () => {
|
|
9
|
+
const [major, minor, patch] = process.versions.node.split(".").map(Number);
|
|
10
|
+
return major >= 18 && minor >= 11;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const isExists = async (path: string) => {
|
|
14
|
+
try {
|
|
15
|
+
await stat(path);
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
7
21
|
export const encodeFileName = (fileName: string, extension?: string) => {
|
|
8
22
|
return (
|
|
9
23
|
fileName.replaceAll("%", "%25").replaceAll("*", "%") +
|
|
@@ -15,12 +29,99 @@ export const decodeFileName = (fileName: string) => {
|
|
|
15
29
|
return fileName.replaceAll("%", "*").replaceAll("*25", "%");
|
|
16
30
|
};
|
|
17
31
|
|
|
32
|
+
export const encode = (
|
|
33
|
+
input: string | number | boolean | null | (string | number | boolean | null)[]
|
|
34
|
+
) => {
|
|
35
|
+
const secureString = (input: string | number | boolean | null) => {
|
|
36
|
+
if (["true", "false"].includes(String(input))) return input ? 1 : 0;
|
|
37
|
+
return typeof input === "string"
|
|
38
|
+
? decodeURIComponent(input)
|
|
39
|
+
.replaceAll("<", "<")
|
|
40
|
+
.replaceAll(">", ">")
|
|
41
|
+
.replaceAll(",", "%2C")
|
|
42
|
+
.replaceAll("|", "%7C")
|
|
43
|
+
.replaceAll("\n", "\\n")
|
|
44
|
+
.replaceAll("\r", "\\r")
|
|
45
|
+
: input;
|
|
46
|
+
};
|
|
47
|
+
return Array.isArray(input)
|
|
48
|
+
? Utils.isArrayOfArrays(input)
|
|
49
|
+
? (input as any[])
|
|
50
|
+
.map((_input) => _input.map(secureString).join(","))
|
|
51
|
+
.join("|")
|
|
52
|
+
: input.map(secureString).join(",")
|
|
53
|
+
: secureString(input);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const decode = (
|
|
57
|
+
input: string | null | number,
|
|
58
|
+
fieldType?: FieldType | FieldType[],
|
|
59
|
+
fieldChildrenType?: FieldType | FieldType[]
|
|
60
|
+
): string | number | boolean | null | (string | number | null | boolean)[] => {
|
|
61
|
+
if (!fieldType) return null;
|
|
62
|
+
const unSecureString = (input: string) =>
|
|
63
|
+
decodeURIComponent(input)
|
|
64
|
+
.replaceAll("<", "<")
|
|
65
|
+
.replaceAll(">", ">")
|
|
66
|
+
.replaceAll("%2C", ",")
|
|
67
|
+
.replaceAll("%7C", "|")
|
|
68
|
+
.replaceAll("\\n", "\n")
|
|
69
|
+
.replaceAll("\\r", "\r") || null;
|
|
70
|
+
if (input === null || input === "") return null;
|
|
71
|
+
if (Array.isArray(fieldType))
|
|
72
|
+
fieldType = Utils.detectFieldType(String(input), fieldType);
|
|
73
|
+
const decodeHelper = (value: string | number | any[]) => {
|
|
74
|
+
if (Array.isArray(value) && fieldType !== "array")
|
|
75
|
+
return value.map(decodeHelper);
|
|
76
|
+
switch (fieldType as FieldType) {
|
|
77
|
+
case "table":
|
|
78
|
+
case "number":
|
|
79
|
+
return isNaN(Number(value)) ? null : Number(value);
|
|
80
|
+
case "boolean":
|
|
81
|
+
return typeof value === "string" ? value === "true" : Boolean(value);
|
|
82
|
+
case "array":
|
|
83
|
+
if (!Array.isArray(value)) return [value];
|
|
84
|
+
if (fieldChildrenType)
|
|
85
|
+
return value.map(
|
|
86
|
+
(v) =>
|
|
87
|
+
decode(
|
|
88
|
+
v,
|
|
89
|
+
Array.isArray(fieldChildrenType)
|
|
90
|
+
? Utils.detectFieldType(v, fieldChildrenType)
|
|
91
|
+
: fieldChildrenType
|
|
92
|
+
) as string | number | boolean | null
|
|
93
|
+
);
|
|
94
|
+
else return value;
|
|
95
|
+
default:
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
return decodeHelper(
|
|
100
|
+
typeof input === "string"
|
|
101
|
+
? input.includes(",")
|
|
102
|
+
? input.includes("|")
|
|
103
|
+
? input
|
|
104
|
+
.split("|")
|
|
105
|
+
.map((_input) => _input.split(",").map(unSecureString))
|
|
106
|
+
: input.split(",").map(unSecureString)
|
|
107
|
+
: unSecureString(input)
|
|
108
|
+
: input
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
18
112
|
export const get = async (
|
|
19
113
|
filePath: string,
|
|
20
|
-
|
|
21
|
-
|
|
114
|
+
lineNumbers?: number | number[],
|
|
115
|
+
fieldType?: FieldType | FieldType[],
|
|
116
|
+
fieldChildrenType?: FieldType | FieldType[]
|
|
22
117
|
) => {
|
|
23
|
-
|
|
118
|
+
let rl: Interface;
|
|
119
|
+
if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
|
|
120
|
+
else
|
|
121
|
+
rl = createInterface({
|
|
122
|
+
input: createReadStream(filePath),
|
|
123
|
+
crlfDelay: Infinity,
|
|
124
|
+
});
|
|
24
125
|
let lines: Record<
|
|
25
126
|
number,
|
|
26
127
|
| string
|
|
@@ -32,21 +133,23 @@ export const get = async (
|
|
|
32
133
|
lineCount = 0;
|
|
33
134
|
|
|
34
135
|
if (!lineNumbers) {
|
|
35
|
-
for await (const line of
|
|
36
|
-
lineCount++,
|
|
136
|
+
for await (const line of rl)
|
|
137
|
+
lineCount++,
|
|
138
|
+
(lines[lineCount] = decode(line, fieldType, fieldChildrenType));
|
|
37
139
|
} else if (lineNumbers === -1) {
|
|
38
|
-
let lastLine;
|
|
39
|
-
for await (const line of
|
|
40
|
-
if (lastLine)
|
|
140
|
+
let lastLine: string;
|
|
141
|
+
for await (const line of rl) lineCount++, (lastLine = line);
|
|
142
|
+
if (lastLine)
|
|
143
|
+
lines = { [lineCount]: decode(lastLine, fieldType, fieldChildrenType) };
|
|
41
144
|
} else {
|
|
42
145
|
let lineNumbersArray = [
|
|
43
146
|
...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
|
|
44
147
|
];
|
|
45
|
-
for await (const line of
|
|
148
|
+
for await (const line of rl) {
|
|
46
149
|
lineCount++;
|
|
47
150
|
if (!lineNumbersArray.includes(lineCount)) continue;
|
|
48
151
|
const indexOfLineCount = lineNumbersArray.indexOf(lineCount);
|
|
49
|
-
lines[lineCount] =
|
|
152
|
+
lines[lineCount] = decode(line, fieldType, fieldChildrenType);
|
|
50
153
|
lineNumbersArray[indexOfLineCount] = 0;
|
|
51
154
|
if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
|
|
52
155
|
}
|
|
@@ -68,34 +171,44 @@ export const replace = async (
|
|
|
68
171
|
string | boolean | number | null | (string | boolean | number | null)[]
|
|
69
172
|
>
|
|
70
173
|
) => {
|
|
71
|
-
if (
|
|
72
|
-
|
|
174
|
+
if (await isExists(filePath)) {
|
|
175
|
+
let rl: Interface, writeStream: WriteStream;
|
|
176
|
+
if (doesSupportReadLines()) {
|
|
177
|
+
const file = await open(filePath, "w+");
|
|
178
|
+
rl = file.readLines();
|
|
73
179
|
writeStream = file.createWriteStream();
|
|
180
|
+
} else {
|
|
181
|
+
rl = createInterface({
|
|
182
|
+
input: createReadStream(filePath),
|
|
183
|
+
crlfDelay: Infinity,
|
|
184
|
+
});
|
|
185
|
+
writeStream = createWriteStream(filePath);
|
|
186
|
+
}
|
|
74
187
|
if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
75
188
|
let lineCount = 0;
|
|
76
|
-
for await (const line of
|
|
189
|
+
for await (const line of rl) {
|
|
77
190
|
lineCount++;
|
|
78
191
|
writeStream.write(
|
|
79
|
-
(lineCount in replacements
|
|
80
|
-
|
|
81
|
-
: line) + "\n"
|
|
192
|
+
(lineCount in replacements ? encode(replacements[lineCount]) : line) +
|
|
193
|
+
"\n"
|
|
82
194
|
);
|
|
83
195
|
}
|
|
84
196
|
} else
|
|
85
|
-
for await (const _line of
|
|
86
|
-
writeStream.write(
|
|
197
|
+
for await (const _line of rl)
|
|
198
|
+
writeStream.write(encode(replacements) + "\n");
|
|
87
199
|
|
|
88
200
|
writeStream.end();
|
|
89
201
|
} else if (typeof replacements === "object" && !Array.isArray(replacements)) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
202
|
+
let writeStream: WriteStream;
|
|
203
|
+
if (doesSupportReadLines())
|
|
204
|
+
writeStream = (await open(filePath, "w")).createWriteStream();
|
|
205
|
+
else writeStream = createWriteStream(filePath);
|
|
206
|
+
const largestLinesNumbers =
|
|
207
|
+
Math.max(...Object.keys(replacements).map(Number)) + 1;
|
|
94
208
|
for (let lineCount = 1; lineCount < largestLinesNumbers; lineCount++) {
|
|
95
209
|
writeStream.write(
|
|
96
|
-
(lineCount in replacements
|
|
97
|
-
|
|
98
|
-
: "") + "\n"
|
|
210
|
+
(lineCount in replacements ? encode(replacements[lineCount]) : "") +
|
|
211
|
+
"\n"
|
|
99
212
|
);
|
|
100
213
|
}
|
|
101
214
|
writeStream.end();
|
|
@@ -108,39 +221,52 @@ export const remove = async (
|
|
|
108
221
|
): Promise<void> => {
|
|
109
222
|
let lineCount = 0;
|
|
110
223
|
|
|
111
|
-
const tempFilePath = `${filePath}.tmp`,
|
|
224
|
+
const tempFilePath = `${filePath}-${Date.now()}.tmp`,
|
|
112
225
|
linesToDeleteArray = [
|
|
113
226
|
...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
|
|
114
|
-
]
|
|
115
|
-
|
|
116
|
-
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
let rl: Interface, writeStream: WriteStream;
|
|
230
|
+
if (doesSupportReadLines()) {
|
|
231
|
+
rl = (await open(filePath)).readLines();
|
|
232
|
+
writeStream = (await open(tempFilePath, "w+")).createWriteStream();
|
|
233
|
+
} else {
|
|
234
|
+
rl = createInterface({
|
|
235
|
+
input: createReadStream(filePath),
|
|
236
|
+
crlfDelay: Infinity,
|
|
237
|
+
});
|
|
238
|
+
writeStream = createWriteStream(tempFilePath);
|
|
239
|
+
}
|
|
117
240
|
|
|
118
|
-
for await (const line of
|
|
241
|
+
for await (const line of rl) {
|
|
119
242
|
lineCount++;
|
|
120
243
|
if (!linesToDeleteArray.includes(lineCount)) {
|
|
121
244
|
writeStream.write(`${line}\n`);
|
|
122
245
|
}
|
|
123
246
|
}
|
|
124
|
-
writeStream.end()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
renameSync(tempFilePath, filePath); // Rename the temp file to the original file name
|
|
247
|
+
writeStream.end(async () => {
|
|
248
|
+
await unlink(filePath); // Remove the original file
|
|
249
|
+
await rename(tempFilePath, filePath); // Rename the temp file to the original file name
|
|
128
250
|
});
|
|
129
251
|
};
|
|
130
252
|
|
|
131
253
|
export const count = async (filePath: string): Promise<number> => {
|
|
132
|
-
let lineCount = 0
|
|
133
|
-
|
|
134
|
-
|
|
254
|
+
let lineCount = 0,
|
|
255
|
+
rl: Interface;
|
|
256
|
+
if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
|
|
257
|
+
else
|
|
258
|
+
rl = createInterface({
|
|
259
|
+
input: createReadStream(filePath),
|
|
260
|
+
crlfDelay: Infinity,
|
|
261
|
+
});
|
|
135
262
|
|
|
136
|
-
for await (const line of
|
|
263
|
+
for await (const line of rl) lineCount++;
|
|
137
264
|
|
|
138
265
|
return lineCount;
|
|
139
266
|
};
|
|
140
267
|
|
|
141
268
|
export const search = async (
|
|
142
269
|
filePath: string,
|
|
143
|
-
fieldType: FieldType,
|
|
144
270
|
operator: ComparisonOperator | ComparisonOperator[],
|
|
145
271
|
comparedAtValue:
|
|
146
272
|
| string
|
|
@@ -149,9 +275,12 @@ export const search = async (
|
|
|
149
275
|
| null
|
|
150
276
|
| (string | number | boolean | null)[],
|
|
151
277
|
logicalOperator?: "and" | "or",
|
|
278
|
+
fieldType?: FieldType | FieldType[],
|
|
279
|
+
fieldChildrenType?: FieldType | FieldType[],
|
|
152
280
|
limit?: number,
|
|
153
281
|
offset?: number,
|
|
154
|
-
readWholeFile?: boolean
|
|
282
|
+
readWholeFile?: boolean,
|
|
283
|
+
secretKey?: string
|
|
155
284
|
): Promise<
|
|
156
285
|
[
|
|
157
286
|
Record<
|
|
@@ -166,7 +295,7 @@ export const search = async (
|
|
|
166
295
|
> => {
|
|
167
296
|
const handleComparisonOperator = (
|
|
168
297
|
operator: ComparisonOperator,
|
|
169
|
-
|
|
298
|
+
originalValue:
|
|
170
299
|
| string
|
|
171
300
|
| number
|
|
172
301
|
| boolean
|
|
@@ -178,77 +307,85 @@ export const search = async (
|
|
|
178
307
|
| boolean
|
|
179
308
|
| null
|
|
180
309
|
| (string | number | boolean | null)[],
|
|
181
|
-
fieldType
|
|
310
|
+
fieldType?: FieldType | FieldType[],
|
|
311
|
+
fieldChildrenType?: FieldType | FieldType[]
|
|
182
312
|
): boolean => {
|
|
183
|
-
|
|
313
|
+
if (Array.isArray(fieldType))
|
|
314
|
+
fieldType = Utils.detectFieldType(String(originalValue), fieldType);
|
|
315
|
+
if (Array.isArray(comparedAtValue) && !["[]", "![]"].includes(operator))
|
|
316
|
+
return comparedAtValue.some((comparedAtValueSingle) =>
|
|
317
|
+
handleComparisonOperator(
|
|
318
|
+
operator,
|
|
319
|
+
originalValue,
|
|
320
|
+
comparedAtValueSingle,
|
|
321
|
+
fieldType
|
|
322
|
+
)
|
|
323
|
+
);
|
|
324
|
+
// check if not array or object // it can't be array or object!
|
|
184
325
|
switch (operator) {
|
|
185
326
|
case "=":
|
|
186
327
|
switch (fieldType) {
|
|
187
328
|
case "password":
|
|
188
|
-
return typeof
|
|
329
|
+
return typeof originalValue === "string" &&
|
|
189
330
|
typeof comparedAtValue === "string"
|
|
190
|
-
? Utils.comparePassword(
|
|
331
|
+
? Utils.comparePassword(originalValue, comparedAtValue)
|
|
191
332
|
: false;
|
|
192
333
|
case "boolean":
|
|
193
|
-
return Number(
|
|
334
|
+
return Number(originalValue) - Number(comparedAtValue) === 0;
|
|
335
|
+
case "id":
|
|
336
|
+
return secretKey && typeof comparedAtValue === "string"
|
|
337
|
+
? Utils.decodeID(comparedAtValue as string, secretKey) ===
|
|
338
|
+
originalValue
|
|
339
|
+
: comparedAtValue === originalValue;
|
|
194
340
|
default:
|
|
195
|
-
return
|
|
341
|
+
return originalValue === comparedAtValue;
|
|
196
342
|
}
|
|
197
343
|
case "!=":
|
|
198
344
|
return !handleComparisonOperator(
|
|
199
345
|
"=",
|
|
200
|
-
|
|
346
|
+
originalValue,
|
|
201
347
|
comparedAtValue,
|
|
202
348
|
fieldType
|
|
203
349
|
);
|
|
204
350
|
case ">":
|
|
205
|
-
return
|
|
206
|
-
value !== null && comparedAtValue !== null && value > comparedAtValue
|
|
207
|
-
);
|
|
351
|
+
return originalValue > comparedAtValue;
|
|
208
352
|
case "<":
|
|
209
|
-
return
|
|
210
|
-
value !== null && comparedAtValue !== null && value < comparedAtValue
|
|
211
|
-
);
|
|
353
|
+
return originalValue < comparedAtValue;
|
|
212
354
|
case ">=":
|
|
213
|
-
return
|
|
214
|
-
value !== null && comparedAtValue !== null && value >= comparedAtValue
|
|
215
|
-
);
|
|
355
|
+
return originalValue >= comparedAtValue;
|
|
216
356
|
case "<=":
|
|
217
|
-
return
|
|
218
|
-
value !== null && comparedAtValue !== null && value <= comparedAtValue
|
|
219
|
-
);
|
|
357
|
+
return originalValue <= comparedAtValue;
|
|
220
358
|
case "[]":
|
|
221
359
|
return (
|
|
222
|
-
(Array.isArray(
|
|
360
|
+
(Array.isArray(originalValue) &&
|
|
223
361
|
Array.isArray(comparedAtValue) &&
|
|
224
|
-
|
|
225
|
-
(Array.isArray(
|
|
362
|
+
originalValue.some(comparedAtValue.includes)) ||
|
|
363
|
+
(Array.isArray(originalValue) &&
|
|
226
364
|
!Array.isArray(comparedAtValue) &&
|
|
227
|
-
|
|
228
|
-
(!Array.isArray(
|
|
365
|
+
originalValue.includes(comparedAtValue)) ||
|
|
366
|
+
(!Array.isArray(originalValue) &&
|
|
229
367
|
Array.isArray(comparedAtValue) &&
|
|
230
|
-
comparedAtValue.includes(
|
|
368
|
+
comparedAtValue.includes(originalValue))
|
|
231
369
|
);
|
|
232
370
|
case "![]":
|
|
233
371
|
return !handleComparisonOperator(
|
|
234
372
|
"[]",
|
|
235
|
-
|
|
373
|
+
originalValue,
|
|
236
374
|
comparedAtValue,
|
|
237
375
|
fieldType
|
|
238
376
|
);
|
|
239
377
|
case "*":
|
|
240
|
-
return (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
);
|
|
378
|
+
return new RegExp(
|
|
379
|
+
`^${(String(comparedAtValue).includes("%")
|
|
380
|
+
? String(comparedAtValue)
|
|
381
|
+
: "%" + String(comparedAtValue) + "%"
|
|
382
|
+
).replace(/%/g, ".*")}$`,
|
|
383
|
+
"i"
|
|
384
|
+
).test(String(originalValue));
|
|
248
385
|
case "!*":
|
|
249
386
|
return !handleComparisonOperator(
|
|
250
387
|
"*",
|
|
251
|
-
|
|
388
|
+
originalValue,
|
|
252
389
|
comparedAtValue,
|
|
253
390
|
fieldType
|
|
254
391
|
);
|
|
@@ -266,13 +403,19 @@ export const search = async (
|
|
|
266
403
|
> = {},
|
|
267
404
|
lineCount = 0,
|
|
268
405
|
foundItems = 0;
|
|
406
|
+
let rl: Interface;
|
|
407
|
+
if (doesSupportReadLines()) rl = (await open(filePath)).readLines();
|
|
408
|
+
else
|
|
409
|
+
rl = createInterface({
|
|
410
|
+
input: createReadStream(filePath),
|
|
411
|
+
crlfDelay: Infinity,
|
|
412
|
+
});
|
|
269
413
|
|
|
270
|
-
const
|
|
271
|
-
columnName = decodeFileName(parse(filePath).name);
|
|
414
|
+
const columnName = decodeFileName(parse(filePath).name);
|
|
272
415
|
|
|
273
|
-
for await (const line of
|
|
416
|
+
for await (const line of rl) {
|
|
274
417
|
lineCount++;
|
|
275
|
-
const decodedLine =
|
|
418
|
+
const decodedLine = decode(line, fieldType, fieldChildrenType);
|
|
276
419
|
if (
|
|
277
420
|
(Array.isArray(operator) &&
|
|
278
421
|
Array.isArray(comparedAtValue) &&
|
|
@@ -318,10 +461,13 @@ export const search = async (
|
|
|
318
461
|
|
|
319
462
|
export default class File {
|
|
320
463
|
static get = get;
|
|
321
|
-
static count = count;
|
|
322
464
|
static remove = remove;
|
|
323
465
|
static search = search;
|
|
324
466
|
static replace = replace;
|
|
467
|
+
static count = count;
|
|
468
|
+
static encode = encode;
|
|
469
|
+
static decode = decode;
|
|
325
470
|
static encodeFileName = encodeFileName;
|
|
326
471
|
static decodeFileName = decodeFileName;
|
|
472
|
+
static isExists = isExists;
|
|
327
473
|
}
|