inibase 1.1.21 → 1.1.23

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/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { parseArgs } from "node:util";
7
7
  import Inison from "inison";
8
8
  import { isExists } from "./file.js";
9
9
  import Inibase, {} from "./index.js";
10
- import { isStringified, isNumber, setField, unsetField } from "./utils.js";
10
+ import { isNumber, isStringified, setField, unsetField } from "./utils.js";
11
11
  const textGreen = (input) => `\u001b[1;32m${input}\u001b[0m`;
12
12
  const textRed = (input) => `\u001b[1;31m${input}\u001b[0m`;
13
13
  const textBlue = (input) => `\u001b[1;34m${input}\u001b[0m`;
@@ -197,7 +197,12 @@ rl.on("line", async (input) => {
197
197
  console.log(`${textRed(" Err:")} Please specify table name`);
198
198
  break;
199
199
  }
200
- let where = undefined, page = undefined, perPage = undefined, columns = undefined, sort = undefined, data = undefined;
200
+ let where = undefined;
201
+ let page = undefined;
202
+ let perPage = undefined;
203
+ let columns = undefined;
204
+ let sort = undefined;
205
+ let data = undefined;
201
206
  if (splitedInput.toSpliced(0, 1).length) {
202
207
  const parsedArgs = parseArgs({
203
208
  args: splitedInput.toSpliced(0, table ? 1 : 2),
package/dist/file.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ComparisonOperator, FieldType, Schema } from "./index.js";
1
+ import { type ComparisonOperator, type Field } from "./index.js";
2
2
  export declare const lock: (folderPath: string, prefix?: string) => Promise<void>;
3
3
  export declare const unlock: (folderPath: string, prefix?: string) => Promise<void>;
4
4
  export declare const write: (filePath: string, data: any) => Promise<void>;
@@ -25,27 +25,30 @@ export declare const encode: (input: string | number | boolean | null | (string
25
25
  * Handles different formats of input, including strings, numbers, and their array representations.
26
26
  *
27
27
  * @param input - The input to be decoded, can be a string, number, or null.
28
- * @param fieldType - Optional type of the field to guide decoding (e.g., 'number', 'boolean').
29
- * @param fieldChildrenType - Optional type for child elements in array inputs.
30
- * @param secretKey - Optional secret key for decoding, can be a string or Buffer.
28
+ * @param field - Field object config.
31
29
  * @returns Decoded value as a string, number, boolean, or array of these, or null if no fieldType or input is null/empty.
32
30
  */
33
- export declare const decode: (input: string | null | number, fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | Schema, secretKey?: string | Buffer) => string | number | boolean | null | (string | number | null | boolean)[];
31
+ export declare const decode: (input: string | null | number, field: Field & {
32
+ databasePath?: string;
33
+ }) => string | number | boolean | null | (string | number | null | boolean)[];
34
34
  /**
35
35
  * Asynchronously reads and decodes data from a file at specified line numbers.
36
36
  * Decodes each line based on specified field types and an optional secret key.
37
37
  *
38
38
  * @param filePath - Path of the file to be read.
39
39
  * @param lineNumbers - Optional line number(s) to read from the file. If -1, reads the last line.
40
- * @param fieldType - Optional type of the field to guide decoding (e.g., 'number', 'boolean').
41
- * @param fieldChildrenType - Optional type for child elements in array inputs.
42
- * @param secretKey - Optional secret key for decoding, can be a string or Buffer.
40
+ * @param field - Field object config.
41
+ * @param readWholeFile - Optional Flag to indicate whether to continue reading the file after reaching the limit.
43
42
  * @returns Promise resolving to a tuple:
44
43
  * 1. Record of line numbers and their decoded content or null if no lines are read.
45
44
  * 2. Total count of lines processed.
46
45
  */
47
- export declare function get(filePath: string, lineNumbers?: number | number[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | Schema, secretKey?: string | Buffer, readWholeFile?: false): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
48
- export declare function get(filePath: string, lineNumbers: undefined | number | number[], fieldType: undefined | FieldType | FieldType[], fieldChildrenType: undefined | FieldType | FieldType[], secretKey: undefined | string | Buffer, readWholeFile: true): Promise<[
46
+ export declare function get(filePath: string, lineNumbers?: number | number[], field?: Field & {
47
+ databasePath?: string;
48
+ }, readWholeFile?: false): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
49
+ export declare function get(filePath: string, lineNumbers: undefined | number | number[], field: undefined | (Field & {
50
+ databasePath?: string;
51
+ }), readWholeFile: true): Promise<[
49
52
  Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null,
50
53
  number
51
54
  ]>;
@@ -95,19 +98,19 @@ export declare const remove: (filePath: string, linesToDelete: number | number[]
95
98
  * @param operator - Comparison operator(s) for evaluation (e.g., '=', '!=', '>', '<').
96
99
  * @param comparedAtValue - Value(s) to compare each line against.
97
100
  * @param logicalOperator - Optional logical operator ('and' or 'or') for combining multiple comparisons.
98
- * @param fieldType - Optional type of the field to guide comparison.
99
- * @param fieldChildrenType - Optional type for child elements in array inputs.
101
+ * @param field - Field object config.
100
102
  * @param limit - Optional limit on the number of results to return.
101
103
  * @param offset - Optional offset to start returning results from.
102
104
  * @param readWholeFile - Flag to indicate whether to continue reading the file after reaching the limit.
103
- * @param secretKey - Optional secret key for decoding, can be a string or Buffer.
104
105
  * @returns Promise resolving to a tuple:
105
106
  * 1. Record of line numbers and their content that match the criteria or null if none.
106
107
  * 2. The count of found items or processed items based on the 'readWholeFile' flag.
107
108
  *
108
109
  * Note: Decodes each line for comparison and can handle complex queries with multiple conditions.
109
110
  */
110
- export declare const search: (filePath: string, operator: ComparisonOperator | ComparisonOperator[], comparedAtValue: string | number | boolean | null | (string | number | boolean | null)[], logicalOperator?: "and" | "or", searchIn?: Set<number>, fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | Schema, limit?: number, offset?: number, readWholeFile?: boolean, secretKey?: string | Buffer) => Promise<[Record<number, string | number | boolean | null | (string | number | boolean | null)[]> | null, number, Set<number> | null]>;
111
+ export declare const search: (filePath: string, operator: ComparisonOperator | ComparisonOperator[], comparedAtValue: string | number | boolean | null | (string | number | boolean | null)[], logicalOperator?: "and" | "or", searchIn?: Set<number>, field?: Field & {
112
+ databasePath?: string;
113
+ }, limit?: number, offset?: number, readWholeFile?: boolean) => Promise<[Record<number, string | number | boolean | null | (string | number | boolean | null)[]> | null, number, Set<number> | null]>;
111
114
  /**
112
115
  * Asynchronously calculates the sum of numerical values from specified lines in a file.
113
116
  *
package/dist/file.js CHANGED
@@ -5,6 +5,7 @@ import { Transform } from "node:stream";
5
5
  import { pipeline } from "node:stream/promises";
6
6
  import { createGunzip, createGzip } from "node:zlib";
7
7
  import Inison from "inison";
8
+ import { globalConfig, } from "./index.js";
8
9
  import { detectFieldType, isArrayOfObjects, isNumber, isObject, isStringified, } from "./utils.js";
9
10
  import { compare, encodeID, exec, gunzip, gzip } from "./utils.server.js";
10
11
  export const lock = async (folderPath, prefix) => {
@@ -131,34 +132,38 @@ const unSecureString = (input) => {
131
132
  * Handles different data types and structures, including nested arrays.
132
133
  *
133
134
  * @param value - The value to be decoded, can be string, number, or array.
134
- * @param fieldType - Optional type of the field to guide decoding (e.g., 'number', 'boolean').
135
- * @param fieldChildrenType - Optional type for children elements, used for arrays.
136
- * @param secretKey - Optional secret key for decoding, can be string or Buffer.
135
+ * @param field - Field object config.
137
136
  * @returns Decoded value, transformed according to the specified field type(s).
138
137
  */
139
- const decodeHelper = (value, fieldType, fieldChildrenType, secretKey) => {
140
- if (Array.isArray(value) && fieldType !== "array")
141
- return value.map((v) => decodeHelper(v, fieldType, fieldChildrenType, secretKey));
142
- switch (fieldType) {
138
+ const decodeHelper = (value, field) => {
139
+ if (Array.isArray(value) && field.type !== "array")
140
+ return value.map((v) => decodeHelper(v, field));
141
+ switch (field.type) {
143
142
  case "number":
144
143
  return isNumber(value) ? Number(value) : null;
145
144
  case "boolean":
146
145
  return typeof value === "string" ? value === "true" : Boolean(value);
147
146
  case "array":
148
147
  if (!Array.isArray(value))
149
- return [value];
150
- if (fieldChildrenType && !isArrayOfObjects(fieldChildrenType))
151
- return fieldChildrenType
152
- ? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
153
- ? detectFieldType(v, fieldChildrenType)
154
- : fieldChildrenType, undefined, secretKey))
155
- : value;
148
+ value = [value];
149
+ if (field.children && !isArrayOfObjects(field.children))
150
+ return value.map((v) => decode(v, {
151
+ ...field,
152
+ type: Array.isArray(field.children)
153
+ ? detectFieldType(v, field.children)
154
+ : field.children,
155
+ }));
156
156
  break;
157
157
  case "table":
158
- case "id":
159
- return isNumber(value) && secretKey
160
- ? encodeID(value, secretKey)
158
+ return isNumber(value) &&
159
+ (!field.table ||
160
+ !field.databasePath ||
161
+ !globalConfig[field.databasePath].tables?.get(field.table)?.config
162
+ .decodeID)
163
+ ? encodeID(value)
161
164
  : value;
165
+ case "id":
166
+ return isNumber(value) ? encodeID(value) : value;
162
167
  default:
163
168
  return value;
164
169
  }
@@ -168,25 +173,21 @@ const decodeHelper = (value, fieldType, fieldChildrenType, secretKey) => {
168
173
  * Handles different formats of input, including strings, numbers, and their array representations.
169
174
  *
170
175
  * @param input - The input to be decoded, can be a string, number, or null.
171
- * @param fieldType - Optional type of the field to guide decoding (e.g., 'number', 'boolean').
172
- * @param fieldChildrenType - Optional type for child elements in array inputs.
173
- * @param secretKey - Optional secret key for decoding, can be a string or Buffer.
176
+ * @param field - Field object config.
174
177
  * @returns Decoded value as a string, number, boolean, or array of these, or null if no fieldType or input is null/empty.
175
178
  */
176
- export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
177
- if (!fieldType)
178
- return null;
179
+ export const decode = (input, field) => {
179
180
  if (input === null || input === "")
180
181
  return undefined;
181
182
  // Detect the fieldType based on the input and the provided array of possible types.
182
- if (Array.isArray(fieldType))
183
- fieldType = detectFieldType(String(input), fieldType);
183
+ if (Array.isArray(field.type))
184
+ field.type = detectFieldType(String(input), field.type);
184
185
  // Decode the input using the decodeHelper function.
185
186
  return decodeHelper(typeof input === "string"
186
187
  ? isStringified(input)
187
188
  ? Inison.unstringify(input)
188
189
  : unSecureString(input)
189
- : input, fieldType, fieldChildrenType, secretKey);
190
+ : input, field);
190
191
  };
191
192
  function _groupIntoRanges(arr, action = "p") {
192
193
  if (arr.length === 0)
@@ -211,25 +212,27 @@ function _groupIntoRanges(arr, action = "p") {
211
212
  ranges.push(start === end ? `${start}` : `${start},${end}`);
212
213
  return ranges.map((range) => `${range}${action}`).join(";");
213
214
  }
214
- export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile = false) {
215
+ export async function get(filePath, lineNumbers, field, readWholeFile = false) {
215
216
  let fileHandle = null;
216
217
  try {
217
218
  fileHandle = await open(filePath, "r");
218
- const rl = createReadLineInternface(filePath, fileHandle), lines = {};
219
+ const rl = createReadLineInternface(filePath, fileHandle);
220
+ const lines = {};
219
221
  let linesCount = 0;
220
222
  if (!lineNumbers) {
221
223
  for await (const line of rl) {
222
224
  linesCount++;
223
- lines[linesCount] = decode(line, fieldType, fieldChildrenType, secretKey);
225
+ lines[linesCount] = decode(line, field);
224
226
  }
225
227
  }
226
228
  else if (lineNumbers == -1) {
227
229
  const escapedFilePath = escapeShellPath(filePath);
228
230
  const command = filePath.endsWith(".gz")
229
231
  ? `zcat ${escapedFilePath} | sed -n '$p'`
230
- : `sed -n '$p' ${escapedFilePath}`, foundedLine = (await exec(command)).stdout.trimEnd();
232
+ : `sed -n '$p' ${escapedFilePath}`;
233
+ const foundedLine = (await exec(command)).stdout.trimEnd();
231
234
  if (foundedLine)
232
- lines[linesCount] = decode(foundedLine, fieldType, fieldChildrenType, secretKey);
235
+ lines[linesCount] = decode(foundedLine, field);
233
236
  }
234
237
  else {
235
238
  lineNumbers = Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers];
@@ -241,7 +244,7 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
241
244
  linesCount++;
242
245
  if (!lineNumbersArray.has(linesCount))
243
246
  continue;
244
- lines[linesCount] = decode(line, fieldType, fieldChildrenType, secretKey);
247
+ lines[linesCount] = decode(line, field);
245
248
  lineNumbersArray.delete(linesCount);
246
249
  }
247
250
  return [lines, linesCount];
@@ -249,10 +252,11 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
249
252
  const escapedFilePath = escapeShellPath(filePath);
250
253
  const command = filePath.endsWith(".gz")
251
254
  ? `zcat ${escapedFilePath} | sed -n '${_groupIntoRanges(lineNumbers)}'`
252
- : `sed -n '${_groupIntoRanges(lineNumbers)}' ${escapedFilePath}`, foundedLines = (await exec(command)).stdout.trimEnd().split("\n");
255
+ : `sed -n '${_groupIntoRanges(lineNumbers)}' ${escapedFilePath}`;
256
+ const foundedLines = (await exec(command)).stdout.trimEnd().split("\n");
253
257
  let index = 0;
254
258
  for (const line of foundedLines) {
255
- lines[lineNumbers[index]] = decode(line, fieldType, fieldChildrenType, secretKey);
259
+ lines[lineNumbers[index]] = decode(line, field);
256
260
  index++;
257
261
  }
258
262
  }
@@ -504,19 +508,17 @@ export const remove = async (filePath, linesToDelete) => {
504
508
  * @param operator - Comparison operator(s) for evaluation (e.g., '=', '!=', '>', '<').
505
509
  * @param comparedAtValue - Value(s) to compare each line against.
506
510
  * @param logicalOperator - Optional logical operator ('and' or 'or') for combining multiple comparisons.
507
- * @param fieldType - Optional type of the field to guide comparison.
508
- * @param fieldChildrenType - Optional type for child elements in array inputs.
511
+ * @param field - Field object config.
509
512
  * @param limit - Optional limit on the number of results to return.
510
513
  * @param offset - Optional offset to start returning results from.
511
514
  * @param readWholeFile - Flag to indicate whether to continue reading the file after reaching the limit.
512
- * @param secretKey - Optional secret key for decoding, can be a string or Buffer.
513
515
  * @returns Promise resolving to a tuple:
514
516
  * 1. Record of line numbers and their content that match the criteria or null if none.
515
517
  * 2. The count of found items or processed items based on the 'readWholeFile' flag.
516
518
  *
517
519
  * Note: Decodes each line for comparison and can handle complex queries with multiple conditions.
518
520
  */
519
- export const search = async (filePath, operator, comparedAtValue, logicalOperator, searchIn, fieldType, fieldChildrenType, limit, offset, readWholeFile, secretKey) => {
521
+ export const search = async (filePath, operator, comparedAtValue, logicalOperator, searchIn, field, limit, offset, readWholeFile) => {
520
522
  // Initialize a Map to store the matching lines with their line numbers.
521
523
  const matchingLines = {};
522
524
  // Initialize counters for line number, found items, and processed items.
@@ -526,10 +528,10 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
526
528
  const meetsConditions = (value) => (Array.isArray(operator) &&
527
529
  Array.isArray(comparedAtValue) &&
528
530
  ((logicalOperator === "or" &&
529
- operator.some((single_operator, index) => compare(single_operator, value, comparedAtValue[index], fieldType))) ||
530
- operator.every((single_operator, index) => compare(single_operator, value, comparedAtValue[index], fieldType)))) ||
531
+ operator.some((single_operator, index) => compare(single_operator, value, comparedAtValue[index], field.type))) ||
532
+ operator.every((single_operator, index) => compare(single_operator, value, comparedAtValue[index], field.type)))) ||
531
533
  (!Array.isArray(operator) &&
532
- compare(operator, value, comparedAtValue, fieldType));
534
+ compare(operator, value, comparedAtValue, field.type));
533
535
  try {
534
536
  // Open the file for reading.
535
537
  fileHandle = await open(filePath, "r");
@@ -544,7 +546,7 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
544
546
  (!searchIn.has(linesCount) || searchIn.has(-linesCount)))
545
547
  continue;
546
548
  // Decode the line for comparison.
547
- const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
549
+ const decodedLine = decode(line, field);
548
550
  // Check if the line meets the specified conditions based on comparison and logical operators.
549
551
  const doesMeetCondition = (Array.isArray(decodedLine) &&
550
552
  decodedLine.flat().some(meetsConditions)) ||
@@ -589,7 +591,8 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
589
591
  * Note: Decodes each line as a number using the 'decode' function. Non-numeric lines contribute 0 to the sum.
590
592
  */
591
593
  export const sum = async (filePath, lineNumbers) => {
592
- let sum = 0, fileHandle = null;
594
+ let sum = 0;
595
+ let fileHandle = null;
593
596
  try {
594
597
  fileHandle = await open(filePath, "r");
595
598
  const rl = createReadLineInternface(filePath, fileHandle);
@@ -600,7 +603,7 @@ export const sum = async (filePath, lineNumbers) => {
600
603
  linesCount++;
601
604
  if (!lineNumbersArray.has(linesCount))
602
605
  continue;
603
- sum += +(decode(line, "number") ?? 0);
606
+ sum += +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
604
607
  lineNumbersArray.delete(linesCount);
605
608
  if (!lineNumbersArray.size)
606
609
  break;
@@ -608,7 +611,7 @@ export const sum = async (filePath, lineNumbers) => {
608
611
  }
609
612
  else
610
613
  for await (const line of rl)
611
- sum += +(decode(line, "number") ?? 0);
614
+ sum += +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
612
615
  return sum;
613
616
  }
614
617
  finally {
@@ -625,7 +628,9 @@ export const sum = async (filePath, lineNumbers) => {
625
628
  * Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the maximum.
626
629
  */
627
630
  export const max = async (filePath, lineNumbers) => {
628
- let max = 0, fileHandle = null, rl = null;
631
+ let max = 0;
632
+ let fileHandle = null;
633
+ let rl = null;
629
634
  try {
630
635
  fileHandle = await open(filePath, "r");
631
636
  rl = createReadLineInternface(filePath, fileHandle);
@@ -636,7 +641,7 @@ export const max = async (filePath, lineNumbers) => {
636
641
  linesCount++;
637
642
  if (!lineNumbersArray.has(linesCount))
638
643
  continue;
639
- const lineContentNum = +(decode(line, "number") ?? 0);
644
+ const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
640
645
  if (lineContentNum > max)
641
646
  max = lineContentNum;
642
647
  lineNumbersArray.delete(linesCount);
@@ -646,7 +651,7 @@ export const max = async (filePath, lineNumbers) => {
646
651
  }
647
652
  else
648
653
  for await (const line of rl) {
649
- const lineContentNum = +(decode(line, "number") ?? 0);
654
+ const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
650
655
  if (lineContentNum > max)
651
656
  max = lineContentNum;
652
657
  }
@@ -666,7 +671,8 @@ export const max = async (filePath, lineNumbers) => {
666
671
  * Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the minimum.
667
672
  */
668
673
  export const min = async (filePath, lineNumbers) => {
669
- let min = 0, fileHandle = null;
674
+ let min = 0;
675
+ let fileHandle = null;
670
676
  try {
671
677
  fileHandle = await open(filePath, "r");
672
678
  const rl = createReadLineInternface(filePath, fileHandle);
@@ -677,7 +683,7 @@ export const min = async (filePath, lineNumbers) => {
677
683
  linesCount++;
678
684
  if (!lineNumbersArray.has(linesCount))
679
685
  continue;
680
- const lineContentNum = +(decode(line, "number") ?? 0);
686
+ const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
681
687
  if (lineContentNum < min)
682
688
  min = lineContentNum;
683
689
  lineNumbersArray.delete(linesCount);
@@ -687,7 +693,7 @@ export const min = async (filePath, lineNumbers) => {
687
693
  }
688
694
  else
689
695
  for await (const line of rl) {
690
- const lineContentNum = +(decode(line, "number") ?? 0);
696
+ const lineContentNum = +(decode(line, { key: "BLABLA", type: "number" }) ?? 0);
691
697
  if (lineContentNum < min)
692
698
  min = lineContentNum;
693
699
  }
package/dist/index.d.ts CHANGED
@@ -53,13 +53,18 @@ declare global {
53
53
  }
54
54
  export type ErrorCodes = "GROUP_UNIQUE" | "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "TABLE_EMPTY" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS" | "INVALID_REGEX_MATCH";
55
55
  export type ErrorLang = "en" | "ar" | "fr" | "es";
56
+ export declare const globalConfig: {
57
+ [database: string]: {
58
+ tables?: Map<string, TableObject>;
59
+ };
60
+ } & {
61
+ salt?: string | Buffer;
62
+ };
56
63
  export default class Inibase {
57
64
  pageInfo: Record<string, pageInfo>;
58
65
  language: ErrorLang;
59
- salt: Buffer;
66
+ fileExtension: string;
60
67
  private databasePath;
61
- private fileExtension;
62
- private tablesMap;
63
68
  private uniqueMap;
64
69
  private totalItems;
65
70
  constructor(database: string, mainFolder?: string, language?: ErrorLang);