inibase 1.0.0-rc.4 → 1.0.0-rc.40

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.
@@ -0,0 +1,103 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import { type Schema } from "./index.js";
3
+ /**
4
+ * Generates a hashed password using SHA-256.
5
+ *
6
+ * @param password - The plain text password to hash.
7
+ * @returns A string containing the salt and the hashed password, separated by a colon.
8
+ */
9
+ export declare const hashPassword: (password: string) => string;
10
+ /**
11
+ * Compares a hashed password with an input password to verify a match.
12
+ *
13
+ * @param hashedPassword - The hashed password, containing both the salt and the hash, separated by a colon.
14
+ * @param inputPassword - The plain text input password to compare against the hashed password.
15
+ * @returns A boolean indicating whether the input password matches the hashed password.
16
+ */
17
+ export declare const comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
18
+ /**
19
+ * Encodes an ID using AES-256-CBC encryption.
20
+ *
21
+ * @param id - The ID to encode, either a number or a string.
22
+ * @param secretKeyOrSalt - The secret key or salt for encryption, can be a string, number, or Buffer.
23
+ * @returns The encoded ID as a hexadecimal string.
24
+ */
25
+ export declare const encodeID: (id: number | string, secretKeyOrSalt: string | number | Buffer) => string;
26
+ /**
27
+ * Decodes an encrypted ID using AES-256-CBC decryption.
28
+ *
29
+ * @param input - The encrypted ID as a hexadecimal string.
30
+ * @param secretKeyOrSalt - The secret key or salt used for decryption, can be a string, number, or Buffer.
31
+ * @returns The decoded ID as a number.
32
+ */
33
+ export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
34
+ /**
35
+ * Finds the last ID number in a schema, potentially decoding it if encrypted.
36
+ *
37
+ * @param schema - The schema to search, defined as an array of schema objects.
38
+ * @param secretKeyOrSalt - The secret key or salt for decoding an encrypted ID, can be a string, number, or Buffer.
39
+ * @returns The last ID number in the schema, decoded if necessary.
40
+ */
41
+ export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
42
+ /**
43
+ * Adds or updates IDs in a schema, encoding them using a provided secret key or salt.
44
+ *
45
+ * @param schema - The schema to update, defined as an array of schema objects.
46
+ * @param oldIndex - The starting index for generating new IDs, defaults to 0.
47
+ * @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
48
+ * @param encodeIDs - If true, IDs will be encoded, else they will remain as numbers.
49
+ * @returns The updated schema with encoded IDs.
50
+ */
51
+ export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer, encodeIDs?: boolean) => (({
52
+ id?: string | number | undefined;
53
+ key: string;
54
+ required?: boolean | undefined;
55
+ } & {
56
+ type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip";
57
+ children?: undefined;
58
+ }) | ({
59
+ id?: string | number | undefined;
60
+ key: string;
61
+ required?: boolean | undefined;
62
+ } & {
63
+ type: "object";
64
+ children: Schema;
65
+ }) | ({
66
+ id?: string | number | undefined;
67
+ key: string;
68
+ required?: boolean | undefined;
69
+ } & {
70
+ type: "array";
71
+ children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip")[];
72
+ }))[];
73
+ export declare const hashString: (str: string) => string;
74
+ export default class UtilsServer {
75
+ static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
76
+ static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
77
+ static hashPassword: (password: string) => string;
78
+ static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
79
+ static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
80
+ static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer, encodeIDs?: boolean | undefined) => (({
81
+ id?: string | number | undefined;
82
+ key: string;
83
+ required?: boolean | undefined;
84
+ } & {
85
+ type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip";
86
+ children?: undefined;
87
+ }) | ({
88
+ id?: string | number | undefined;
89
+ key: string;
90
+ required?: boolean | undefined;
91
+ } & {
92
+ type: "object";
93
+ children: Schema;
94
+ }) | ({
95
+ id?: string | number | undefined;
96
+ key: string;
97
+ required?: boolean | undefined;
98
+ } & {
99
+ type: "array";
100
+ children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "json" | "date" | "password" | "ip")[];
101
+ }))[];
102
+ static hashString: (str: string) => string;
103
+ }
@@ -0,0 +1,122 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, } from "node:crypto";
2
+ import { isArrayOfObjects, isNumber, isValidID } from "./utils.js";
3
+ /**
4
+ * Generates a hashed password using SHA-256.
5
+ *
6
+ * @param password - The plain text password to hash.
7
+ * @returns A string containing the salt and the hashed password, separated by a colon.
8
+ */
9
+ export const hashPassword = (password) => {
10
+ const salt = randomBytes(16).toString("hex");
11
+ const hash = createHash("sha256")
12
+ .update(password + salt)
13
+ .digest("hex");
14
+ return `${salt}:${hash}`;
15
+ };
16
+ /**
17
+ * Compares a hashed password with an input password to verify a match.
18
+ *
19
+ * @param hashedPassword - The hashed password, containing both the salt and the hash, separated by a colon.
20
+ * @param inputPassword - The plain text input password to compare against the hashed password.
21
+ * @returns A boolean indicating whether the input password matches the hashed password.
22
+ */
23
+ export const comparePassword = (hashedPassword, inputPassword) => {
24
+ const [salt, originalHash] = hashedPassword.split(":");
25
+ const inputHash = createHash("sha256")
26
+ .update(inputPassword + salt)
27
+ .digest("hex");
28
+ return inputHash === originalHash;
29
+ };
30
+ /**
31
+ * Encodes an ID using AES-256-CBC encryption.
32
+ *
33
+ * @param id - The ID to encode, either a number or a string.
34
+ * @param secretKeyOrSalt - The secret key or salt for encryption, can be a string, number, or Buffer.
35
+ * @returns The encoded ID as a hexadecimal string.
36
+ */
37
+ export const encodeID = (id, secretKeyOrSalt) => {
38
+ let cipher;
39
+ if (Buffer.isBuffer(secretKeyOrSalt))
40
+ cipher = createCipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
41
+ else {
42
+ const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
43
+ cipher = createCipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
44
+ }
45
+ return cipher.update(id.toString(), "utf8", "hex") + cipher.final("hex");
46
+ };
47
+ /**
48
+ * Decodes an encrypted ID using AES-256-CBC decryption.
49
+ *
50
+ * @param input - The encrypted ID as a hexadecimal string.
51
+ * @param secretKeyOrSalt - The secret key or salt used for decryption, can be a string, number, or Buffer.
52
+ * @returns The decoded ID as a number.
53
+ */
54
+ export const decodeID = (input, secretKeyOrSalt) => {
55
+ let decipher;
56
+ if (Buffer.isBuffer(secretKeyOrSalt))
57
+ decipher = createDecipheriv("aes-256-cbc", secretKeyOrSalt, secretKeyOrSalt.subarray(0, 16));
58
+ else {
59
+ const salt = scryptSync(secretKeyOrSalt.toString(), (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
60
+ decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
61
+ }
62
+ return Number(decipher.update(input, "hex", "utf8") + decipher.final("utf8"));
63
+ };
64
+ /**
65
+ * Finds the last ID number in a schema, potentially decoding it if encrypted.
66
+ *
67
+ * @param schema - The schema to search, defined as an array of schema objects.
68
+ * @param secretKeyOrSalt - The secret key or salt for decoding an encrypted ID, can be a string, number, or Buffer.
69
+ * @returns The last ID number in the schema, decoded if necessary.
70
+ */
71
+ export const findLastIdNumber = (schema, secretKeyOrSalt) => {
72
+ const lastField = schema[schema.length - 1];
73
+ if (lastField) {
74
+ if ((lastField.type === "array" || lastField.type === "object") &&
75
+ isArrayOfObjects(lastField.children))
76
+ return findLastIdNumber(lastField.children, secretKeyOrSalt);
77
+ else if (lastField.id)
78
+ return isValidID(lastField.id)
79
+ ? decodeID(lastField.id, secretKeyOrSalt)
80
+ : lastField.id;
81
+ }
82
+ return 0;
83
+ };
84
+ /**
85
+ * Adds or updates IDs in a schema, encoding them using a provided secret key or salt.
86
+ *
87
+ * @param schema - The schema to update, defined as an array of schema objects.
88
+ * @param oldIndex - The starting index for generating new IDs, defaults to 0.
89
+ * @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
90
+ * @param encodeIDs - If true, IDs will be encoded, else they will remain as numbers.
91
+ * @returns The updated schema with encoded IDs.
92
+ */
93
+ export const addIdToSchema = (schema, oldIndex = 0, secretKeyOrSalt, encodeIDs) => schema.map((field) => {
94
+ if (!field.id) {
95
+ oldIndex++;
96
+ field.id = encodeIDs ? encodeID(oldIndex, secretKeyOrSalt) : oldIndex;
97
+ }
98
+ else {
99
+ if (!isNumber(field.id))
100
+ oldIndex = decodeID(field.id, secretKeyOrSalt);
101
+ else {
102
+ oldIndex = field.id;
103
+ field.id = encodeIDs ? encodeID(field.id, secretKeyOrSalt) : field.id;
104
+ }
105
+ }
106
+ if ((field.type === "array" || field.type === "object") &&
107
+ isArrayOfObjects(field.children)) {
108
+ field.children = addIdToSchema(field.children, oldIndex, secretKeyOrSalt, encodeIDs);
109
+ oldIndex += field.children.length;
110
+ }
111
+ return field;
112
+ });
113
+ export const hashString = (str) => createHash("sha256").update(str).digest("hex");
114
+ export default class UtilsServer {
115
+ static encodeID = encodeID;
116
+ static decodeID = decodeID;
117
+ static hashPassword = hashPassword;
118
+ static comparePassword = comparePassword;
119
+ static findLastIdNumber = findLastIdNumber;
120
+ static addIdToSchema = addIdToSchema;
121
+ static hashString = hashString;
122
+ }
package/package.json CHANGED
@@ -1,37 +1,88 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.4",
4
- "description": "File-based Relational Database for large data",
5
- "main": "index.ts",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/inicontent/inibase.git"
3
+ "version": "1.0.0-rc.40",
4
+ "author": {
5
+ "name": "Karim Amahtil",
6
+ "email": "karim.amahtil@gmail.com"
9
7
  },
8
+ "repository": "inicontent/inibase",
9
+ "main": "./dist/index.js",
10
+ "exports": {
11
+ ".": "./dist/index.js",
12
+ "./thread": "./dist/index.thread.js",
13
+ "./file": "./dist/file.js",
14
+ "./file.thread": "./dist/file.thread.js",
15
+ "./config": "./dist/config.js",
16
+ "./utils": "./dist/utils.js",
17
+ "./utils.server": "./dist/utils.server.js"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/inicontent/inibase/issues"
21
+ },
22
+ "description": "A file-based & memory-efficient, serverless, ACID compliant, relational database management system",
23
+ "engines": {
24
+ "node": ">=16"
25
+ },
26
+ "files": [
27
+ "/dist"
28
+ ],
29
+ "funding": "https://github.com/sponsors/inicontent",
30
+ "homepage": "https://github.com/inicontent/inibase#readme",
10
31
  "keywords": [
11
- "db",
12
32
  "nosql",
13
- "mongoose",
33
+ "sqlite",
34
+ "sql",
35
+ "supabase",
36
+ "better-sqlite",
14
37
  "mongodb",
38
+ "firebase",
39
+ "postgresql",
40
+ "rdms",
15
41
  "database",
42
+ "db",
43
+ "mongoose",
16
44
  "relational",
17
45
  "local",
46
+ "file",
18
47
  "storage",
19
48
  "json",
20
- "sql",
21
- "sqlite",
22
- "supabase",
23
- "firebase"
49
+ "pocketbase"
24
50
  ],
25
- "author": "Inicontent",
26
51
  "license": "MIT",
27
- "bugs": {
28
- "url": "https://github.com/inicontent/inibase/issues"
52
+ "type": "module",
53
+ "types": "./dist",
54
+ "typesVersions": {
55
+ "*": {
56
+ "thread": [
57
+ "./dist/index.thread.d.ts"
58
+ ],
59
+ "file": [
60
+ "./dist/file.d.ts"
61
+ ],
62
+ "file.thread": [
63
+ "./dist/file.thread.d.ts"
64
+ ],
65
+ "utils": [
66
+ "./dist/utils.d.ts"
67
+ ],
68
+ "config": [
69
+ "./dist/config.d.ts"
70
+ ],
71
+ "utils.server": [
72
+ "./dist/utils.server.d.ts"
73
+ ]
74
+ }
29
75
  },
30
- "homepage": "https://github.com/inicontent/inibase#readme",
31
76
  "devDependencies": {
32
- "@types/node": "^20.6.0"
77
+ "@types/node": "^20.10.6",
78
+ "tinybench": "^2.6.0",
79
+ "typescript": "^5.3.3"
33
80
  },
34
81
  "scripts": {
35
- "test": "echo \"Error: no test specified\" && exit 1"
82
+ "build": "npx tsc",
83
+ "test": "npx tsx watch --expose-gc --env-file=.env ./index.test",
84
+ "benchmark": "npx tsx watch --env-file=.env ./benchmark/index",
85
+ "benchmark:single": "npx tsx --expose-gc --env-file=.env ./benchmark/single",
86
+ "benchmark:bulk": "npx tsx --expose-gc --env-file=.env ./benchmark/bulk"
36
87
  }
37
88
  }
package/file.ts DELETED
@@ -1,327 +0,0 @@
1
- import { createWriteStream, unlinkSync, renameSync, existsSync } from "fs";
2
- import { open } from "fs/promises";
3
- import { parse } from "path";
4
- import { ComparisonOperator, FieldType } from ".";
5
- import Utils from "./utils";
6
-
7
- export const encodeFileName = (fileName: string, extension?: string) => {
8
- return (
9
- fileName.replaceAll("%", "%25").replaceAll("*", "%") +
10
- (extension ? `.${extension}` : "")
11
- );
12
- };
13
-
14
- export const decodeFileName = (fileName: string) => {
15
- return fileName.replaceAll("%", "*").replaceAll("*25", "%");
16
- };
17
-
18
- export const get = async (
19
- filePath: string,
20
- fieldType?: FieldType,
21
- lineNumbers?: number | number[]
22
- ) => {
23
- const file = await open(filePath);
24
- let lines: Record<
25
- number,
26
- | string
27
- | number
28
- | boolean
29
- | (string | number | boolean | (string | number | boolean)[] | null)[]
30
- | null
31
- > = {},
32
- lineCount = 0;
33
-
34
- if (!lineNumbers) {
35
- for await (const line of file.readLines())
36
- lineCount++, (lines[lineCount] = Utils.decode(line, fieldType));
37
- } else if (lineNumbers === -1) {
38
- let lastLine;
39
- for await (const line of file.readLines()) lineCount++, (lastLine = line);
40
- if (lastLine) lines = { [lineCount]: Utils.decode(lastLine, fieldType) };
41
- } else {
42
- let lineNumbersArray = [
43
- ...(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]),
44
- ];
45
- for await (const line of file.readLines()) {
46
- lineCount++;
47
- if (!lineNumbersArray.includes(lineCount)) continue;
48
- const indexOfLineCount = lineNumbersArray.indexOf(lineCount);
49
- lines[lineCount] = Utils.decode(line, fieldType);
50
- lineNumbersArray[indexOfLineCount] = 0;
51
- if (!lineNumbersArray.filter((lineN) => lineN !== 0).length) break;
52
- }
53
- }
54
-
55
- return lines ?? null;
56
- };
57
-
58
- export const replace = async (
59
- filePath: string,
60
- replacements:
61
- | string
62
- | number
63
- | boolean
64
- | null
65
- | (string | number | boolean | null)[]
66
- | Record<
67
- number,
68
- string | boolean | number | null | (string | boolean | number | null)[]
69
- >
70
- ) => {
71
- if (existsSync(filePath)) {
72
- const file = await open(filePath, "w+"),
73
- writeStream = file.createWriteStream();
74
- if (typeof replacements === "object" && !Array.isArray(replacements)) {
75
- let lineCount = 0;
76
- for await (const line of file.readLines()) {
77
- lineCount++;
78
- writeStream.write(
79
- (lineCount in replacements
80
- ? Utils.encode(replacements[lineCount])
81
- : line) + "\n"
82
- );
83
- }
84
- } else
85
- for await (const _line of file.readLines())
86
- writeStream.write(Utils.encode(replacements) + "\n");
87
-
88
- writeStream.end();
89
- } else if (typeof replacements === "object" && !Array.isArray(replacements)) {
90
- const file = await open(filePath, "w"),
91
- writeStream = file.createWriteStream(),
92
- largestLinesNumbers =
93
- Math.max(...Object.keys(replacements).map(Number)) + 1;
94
- for (let lineCount = 1; lineCount < largestLinesNumbers; lineCount++) {
95
- writeStream.write(
96
- (lineCount in replacements
97
- ? Utils.encode(replacements[lineCount])
98
- : "") + "\n"
99
- );
100
- }
101
- writeStream.end();
102
- }
103
- };
104
-
105
- export const remove = async (
106
- filePath: string,
107
- linesToDelete: number | number[]
108
- ): Promise<void> => {
109
- let lineCount = 0;
110
-
111
- const tempFilePath = `${filePath}.tmp`,
112
- linesToDeleteArray = [
113
- ...(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]),
114
- ],
115
- writeStream = createWriteStream(tempFilePath),
116
- file = await open(filePath);
117
-
118
- for await (const line of file.readLines()) {
119
- lineCount++;
120
- if (!linesToDeleteArray.includes(lineCount)) {
121
- writeStream.write(`${line}\n`);
122
- }
123
- }
124
- writeStream.end();
125
- writeStream.on("finish", () => {
126
- unlinkSync(filePath); // Remove the original file
127
- renameSync(tempFilePath, filePath); // Rename the temp file to the original file name
128
- });
129
- };
130
-
131
- export const count = async (filePath: string): Promise<number> => {
132
- let lineCount = 0;
133
-
134
- const file = await open(filePath);
135
-
136
- for await (const line of file.readLines()) lineCount++;
137
-
138
- return lineCount;
139
- };
140
-
141
- export const search = async (
142
- filePath: string,
143
- fieldType: FieldType,
144
- operator: ComparisonOperator | ComparisonOperator[],
145
- comparedAtValue:
146
- | string
147
- | number
148
- | boolean
149
- | null
150
- | (string | number | boolean | null)[],
151
- logicalOperator?: "and" | "or",
152
- limit?: number,
153
- offset?: number,
154
- readWholeFile?: boolean
155
- ): Promise<
156
- [
157
- Record<
158
- number,
159
- Record<
160
- string,
161
- string | number | boolean | (string | number | boolean | null)[] | null
162
- >
163
- > | null,
164
- number
165
- ]
166
- > => {
167
- const handleComparisonOperator = (
168
- operator: ComparisonOperator,
169
- value:
170
- | string
171
- | number
172
- | boolean
173
- | null
174
- | (string | number | boolean | null)[],
175
- comparedAtValue:
176
- | string
177
- | number
178
- | boolean
179
- | null
180
- | (string | number | boolean | null)[],
181
- fieldType: FieldType
182
- ): boolean => {
183
- // check if not array or object
184
- switch (operator) {
185
- case "=":
186
- switch (fieldType) {
187
- case "password":
188
- return typeof value === "string" &&
189
- typeof comparedAtValue === "string"
190
- ? Utils.comparePassword(value, comparedAtValue)
191
- : false;
192
- case "boolean":
193
- return Number(value) - Number(comparedAtValue) === 0;
194
- default:
195
- return value === comparedAtValue;
196
- }
197
- case "!=":
198
- return !handleComparisonOperator(
199
- "=",
200
- value,
201
- comparedAtValue,
202
- fieldType
203
- );
204
- case ">":
205
- return (
206
- value !== null && comparedAtValue !== null && value > comparedAtValue
207
- );
208
- case "<":
209
- return (
210
- value !== null && comparedAtValue !== null && value < comparedAtValue
211
- );
212
- case ">=":
213
- return (
214
- value !== null && comparedAtValue !== null && value >= comparedAtValue
215
- );
216
- case "<=":
217
- return (
218
- value !== null && comparedAtValue !== null && value <= comparedAtValue
219
- );
220
- case "[]":
221
- return (
222
- (Array.isArray(value) &&
223
- Array.isArray(comparedAtValue) &&
224
- value.some(comparedAtValue.includes)) ||
225
- (Array.isArray(value) &&
226
- !Array.isArray(comparedAtValue) &&
227
- value.includes(comparedAtValue)) ||
228
- (!Array.isArray(value) &&
229
- Array.isArray(comparedAtValue) &&
230
- comparedAtValue.includes(value))
231
- );
232
- case "![]":
233
- return !handleComparisonOperator(
234
- "[]",
235
- value,
236
- comparedAtValue,
237
- fieldType
238
- );
239
- case "*":
240
- return (
241
- value !== null &&
242
- comparedAtValue !== null &&
243
- new RegExp(
244
- `^${comparedAtValue.toString().replace(/%/g, ".*")}$`,
245
- "i"
246
- ).test(value.toString())
247
- );
248
- case "!*":
249
- return !handleComparisonOperator(
250
- "*",
251
- value,
252
- comparedAtValue,
253
- fieldType
254
- );
255
- default:
256
- throw new Error(operator);
257
- }
258
- };
259
-
260
- let RETURN: Record<
261
- number,
262
- Record<
263
- string,
264
- string | number | boolean | null | (string | number | boolean | null)[]
265
- >
266
- > = {},
267
- lineCount = 0,
268
- foundItems = 0;
269
-
270
- const file = await open(filePath),
271
- columnName = decodeFileName(parse(filePath).name);
272
-
273
- for await (const line of file.readLines()) {
274
- lineCount++;
275
- const decodedLine = Utils.decode(line, fieldType);
276
- if (
277
- (Array.isArray(operator) &&
278
- Array.isArray(comparedAtValue) &&
279
- ((logicalOperator &&
280
- logicalOperator === "or" &&
281
- operator.some((single_operator, index) =>
282
- handleComparisonOperator(
283
- single_operator,
284
- decodedLine,
285
- comparedAtValue[index],
286
- fieldType
287
- )
288
- )) ||
289
- operator.every((single_operator, index) =>
290
- handleComparisonOperator(
291
- single_operator,
292
- decodedLine,
293
- comparedAtValue[index],
294
- fieldType
295
- )
296
- ))) ||
297
- (!Array.isArray(operator) &&
298
- handleComparisonOperator(
299
- operator,
300
- decodedLine,
301
- comparedAtValue,
302
- fieldType
303
- ))
304
- ) {
305
- foundItems++;
306
- if (offset && foundItems < offset) continue;
307
- if (limit && foundItems > limit)
308
- if (readWholeFile) continue;
309
- else break;
310
- if (!RETURN[lineCount]) RETURN[lineCount] = {};
311
- RETURN[lineCount][columnName] = decodedLine;
312
- }
313
- }
314
- if (foundItems) {
315
- return [RETURN, readWholeFile ? foundItems : foundItems - 1];
316
- } else return [null, 0];
317
- };
318
-
319
- export default class File {
320
- static get = get;
321
- static count = count;
322
- static remove = remove;
323
- static search = search;
324
- static replace = replace;
325
- static encodeFileName = encodeFileName;
326
- static decodeFileName = decodeFileName;
327
- }