inibase 1.0.0-rc.27 → 1.0.0-rc.28

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/file.d.ts CHANGED
@@ -43,7 +43,7 @@ export declare const decode: (input: string | null | number, fieldType?: FieldTy
43
43
  * 1. Record of line numbers and their decoded content or null if no lines are read.
44
44
  * 2. Total count of lines processed.
45
45
  */
46
- export declare function get(filePath: string, lineNumbers?: number | number[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[], secretKey?: string | Buffer): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
46
+ export declare function get(filePath: string, lineNumbers?: number | number[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[], secretKey?: string | Buffer, readWholeFile?: false): Promise<Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null>;
47
47
  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<[
48
48
  Record<number, string | number | boolean | null | (string | number | boolean | (string | number | boolean)[] | null)[]> | null,
49
49
  number
package/dist/file.js CHANGED
@@ -187,46 +187,29 @@ const reverseJoinMultidimensionalArray = (joinedString) => {
187
187
  * @returns Decoded value, transformed according to the specified field type(s).
188
188
  */
189
189
  const decodeHelper = (value, fieldType, fieldChildrenType, secretKey) => {
190
- // Use a stack-based approach for efficient processing without recursion.
191
- const stack = [{ value }];
192
- while (stack.length > 0) {
193
- // Explicitly check if stack.pop() is not undefined.
194
- const stackItem = stack.pop();
195
- if (!stackItem) {
196
- // Skip the rest of the loop if the stack item is undefined.
197
- continue;
198
- }
199
- const { value } = stackItem;
200
- if (Array.isArray(value) && fieldType !== "array") {
201
- // If the value is an array and the fieldType is not 'array', process each element.
202
- stack.push(...value.map((v) => ({ value: v })));
203
- }
204
- else {
205
- switch (fieldType) {
206
- // Handle different field types with appropriate decoding logic.
207
- case "table":
208
- case "number":
209
- return isNumber(value) ? Number(value) : null;
210
- case "boolean":
211
- return typeof value === "string" ? value === "true" : Boolean(value);
212
- case "array":
213
- if (!Array.isArray(value))
214
- return [value];
215
- if (fieldChildrenType)
216
- // Decode each element in the array based on the specified fieldChildrenType.
217
- return fieldChildrenType
218
- ? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
219
- ? detectFieldType(v, fieldChildrenType)
220
- : fieldChildrenType, undefined, secretKey))
221
- : value;
222
- case "id":
223
- return isNumber(value) && secretKey
224
- ? encodeID(value, secretKey)
225
- : value;
226
- default:
227
- return value;
228
- }
229
- }
190
+ if (Array.isArray(value) && fieldType !== "array")
191
+ return value.map((v) => decodeHelper(v, fieldType, fieldChildrenType, secretKey));
192
+ switch (fieldType) {
193
+ case "table":
194
+ case "number":
195
+ return isNumber(value) ? Number(value) : null;
196
+ case "boolean":
197
+ return typeof value === "string" ? value === "true" : Boolean(value);
198
+ case "array":
199
+ if (!Array.isArray(value))
200
+ return [value];
201
+ if (fieldChildrenType)
202
+ return fieldChildrenType
203
+ ? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
204
+ ? detectFieldType(v, fieldChildrenType)
205
+ : fieldChildrenType, undefined, secretKey))
206
+ : value;
207
+ case "id":
208
+ return isNumber(value) && secretKey
209
+ ? encodeID(value, secretKey)
210
+ : value;
211
+ default:
212
+ return value;
230
213
  }
231
214
  };
232
215
  /**
@@ -254,7 +237,7 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
254
237
  : unSecureString(input)
255
238
  : input, fieldType, fieldChildrenType, secretKey);
256
239
  };
257
- export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile) {
240
+ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile = false) {
258
241
  let fileHandle, rl;
259
242
  try {
260
243
  fileHandle = await open(filePath, "r");
@@ -303,32 +286,49 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
303
286
  * Note: If the file doesn't exist and replacements is an object, it creates a new file with the specified replacements.
304
287
  */
305
288
  export const replace = async (filePath, replacements) => {
306
- let fileHandle, fileTempHandle, rl;
307
289
  const fileTempPath = filePath.replace(/([^/]+)\/?$/, `.tmp/${Date.now()}-$1`);
308
- try {
309
- let linesCount = 0;
310
- fileHandle = await open(filePath, "r");
311
- fileTempHandle = await open(fileTempPath, "w");
312
- rl = readLineInternface(fileHandle);
313
- await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
314
- transform(line, encoding, callback) {
315
- linesCount++;
316
- const replacement = isObject(replacements)
317
- ? replacements.hasOwnProperty(linesCount)
318
- ? replacements[linesCount]
319
- : line
320
- : replacements;
321
- callback(null, replacement + "\n");
322
- },
323
- }));
324
- return [fileTempPath, filePath];
290
+ if (await isExists(filePath)) {
291
+ let fileHandle, fileTempHandle, rl;
292
+ try {
293
+ let linesCount = 0;
294
+ fileHandle = await open(filePath, "r");
295
+ fileTempHandle = await open(fileTempPath, "w");
296
+ rl = readLineInternface(fileHandle);
297
+ await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
298
+ transform(line, encoding, callback) {
299
+ linesCount++;
300
+ const replacement = isObject(replacements)
301
+ ? replacements.hasOwnProperty(linesCount)
302
+ ? replacements[linesCount]
303
+ : line
304
+ : replacements;
305
+ return callback(null, replacement + "\n");
306
+ },
307
+ }));
308
+ return [fileTempPath, filePath];
309
+ }
310
+ finally {
311
+ // Ensure that file handles are closed, even if an error occurred
312
+ rl?.close();
313
+ await fileHandle?.close();
314
+ await fileTempHandle?.close();
315
+ }
325
316
  }
326
- finally {
327
- // Ensure that file handles are closed, even if an error occurred
328
- rl?.close();
329
- await fileHandle?.close();
330
- await fileTempHandle?.close();
317
+ else if (isObject(replacements)) {
318
+ let replacementsKeys = Object.keys(replacements)
319
+ .map(Number)
320
+ .toSorted((a, b) => a - b);
321
+ await write(fileTempPath, "\n".repeat(replacementsKeys[0] - 1) +
322
+ replacementsKeys
323
+ .map((lineNumber, index) => index === 0 || lineNumber - replacementsKeys[index - 1] - 1 === 0
324
+ ? replacements[lineNumber]
325
+ : "\n".repeat(lineNumber - replacementsKeys[index - 1] - 1) +
326
+ replacements[lineNumber])
327
+ .join("\n") +
328
+ "\n");
329
+ return [fileTempPath, filePath];
331
330
  }
331
+ return [];
332
332
  };
333
333
  /**
334
334
  * Asynchronously appends data to the beginning of a file.
@@ -351,10 +351,10 @@ export const append = async (filePath, data) => {
351
351
  transform(line, encoding, callback) {
352
352
  if (!isAppended) {
353
353
  isAppended = true;
354
- callback(null, `${Array.isArray(data) ? data.join("\n") : data}\n${line}\n`);
354
+ return callback(null, `${Array.isArray(data) ? data.join("\n") : data}\n${line}\n`);
355
355
  }
356
356
  else
357
- callback(null, `${line}\n`);
357
+ return callback(null, `${line}\n`);
358
358
  },
359
359
  }));
360
360
  }
@@ -386,9 +386,9 @@ export const remove = async (filePath, linesToDelete) => {
386
386
  await _pipeline(rl, fileTempHandle.createWriteStream(), new Transform({
387
387
  transform(line, encoding, callback) {
388
388
  linesCount++;
389
- if (!linesToDeleteArray.has(linesCount))
390
- callback(null, `${line}\n`);
391
- callback();
389
+ return !linesToDeleteArray.has(linesCount)
390
+ ? callback(null, `${line}\n`)
391
+ : callback();
392
392
  },
393
393
  }));
394
394
  await fileTempHandle.close();
package/dist/index.d.ts CHANGED
@@ -13,23 +13,25 @@ type FieldDefault = {
13
13
  };
14
14
  type FieldStringType = {
15
15
  type: Exclude<FieldType, "array" | "object">;
16
+ children?: never;
16
17
  };
17
18
  type FieldStringArrayType = {
18
- type: Exclude<FieldType, "array" | "object">[];
19
+ type: Array<Exclude<FieldType, "array" | "object">>;
20
+ children?: never;
19
21
  };
20
22
  type FieldArrayType = {
21
23
  type: "array";
22
24
  children: Exclude<FieldType, "array"> | Exclude<FieldType, "array">[] | Schema;
23
25
  };
24
26
  type FieldArrayArrayType = {
25
- type: ["array", ...Exclude<FieldType, "array" | "object">[]];
27
+ type: Array<"array" | Exclude<FieldType, "array" | "object">>;
26
28
  children: Exclude<FieldType, "array" | "object"> | Exclude<FieldType, "array" | "object">[];
27
29
  };
28
30
  type FieldObjectType = {
29
31
  type: "object";
30
32
  children: Schema;
31
33
  };
32
- export type Field = FieldDefault & (FieldStringType | FieldStringArrayType | FieldObjectType | FieldArrayType | FieldArrayArrayType);
34
+ export type Field = FieldDefault & (FieldStringType | (FieldStringArrayType & FieldArrayArrayType) | FieldObjectType | FieldArrayType);
33
35
  export type Schema = Field[];
34
36
  export interface Options {
35
37
  page?: number;
@@ -66,7 +68,7 @@ export default class Inibase {
66
68
  private throwError;
67
69
  setTableSchema(tableName: string, schema: Schema): Promise<void>;
68
70
  getTableSchema(tableName: string): Promise<Schema | undefined>;
69
- getField(keyPath: string, schema: Schema): Field | null;
71
+ getField(keyPath: string, schema: Schema): (FieldDefault & FieldStringType) | (FieldDefault & FieldObjectType) | (FieldDefault & FieldArrayType) | null;
70
72
  private validateData;
71
73
  private formatField;
72
74
  private formatData;
package/dist/index.js CHANGED
@@ -303,7 +303,9 @@ export default class Inibase {
303
303
  const path = join(this.folder, this.database, tableName);
304
304
  let RETURN = {};
305
305
  for await (const field of schema) {
306
- if (field.type === "array" && field.children) {
306
+ if ((field.type === "array" ||
307
+ (Array.isArray(field.type) && field.type.includes("array"))) &&
308
+ field.children) {
307
309
  if (Utils.isArrayOfObjects(field.children)) {
308
310
  if (field.children.filter((children) => children.type === "array" &&
309
311
  Utils.isArrayOfObjects(children.children)).length) {
@@ -380,6 +382,7 @@ export default class Inibase {
380
382
  });
381
383
  }
382
384
  else if (field.children === "table" ||
385
+ (Array.isArray(field.type) && field.type.includes("table")) ||
383
386
  (Array.isArray(field.children) && field.children.includes("table"))) {
384
387
  if (options.columns)
385
388
  options.columns = options.columns
@@ -731,7 +734,7 @@ export default class Inibase {
731
734
  if (onlyLinesNumbers)
732
735
  return Object.keys(RETURN).map(Number);
733
736
  const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]);
734
- RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter((field) => !alreadyExistsColumns.includes(field.key)), Object.keys(RETURN).map(Number), options)));
737
+ RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter(({ key }) => !alreadyExistsColumns.includes(key)), Object.keys(RETURN).map(Number), options)));
735
738
  if (Config.isCacheEnabled)
736
739
  await File.write(cachedFilePath, Array.from(linesNumbers).join(","), true);
737
740
  }
@@ -47,7 +47,28 @@ export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string
47
47
  * @param secretKeyOrSalt - The secret key or salt for encoding IDs, can be a string, number, or Buffer.
48
48
  * @returns The updated schema with encoded IDs.
49
49
  */
50
- export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
50
+ export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => (({
51
+ id?: string | number | undefined;
52
+ key: string;
53
+ required?: boolean | undefined;
54
+ } & {
55
+ type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip";
56
+ children?: undefined;
57
+ }) | ({
58
+ id?: string | number | undefined;
59
+ key: string;
60
+ required?: boolean | undefined;
61
+ } & {
62
+ type: "object";
63
+ children: Schema;
64
+ }) | ({
65
+ id?: string | number | undefined;
66
+ key: string;
67
+ required?: boolean | undefined;
68
+ } & {
69
+ type: "array";
70
+ children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip")[];
71
+ }))[];
51
72
  export declare const hashObject: (obj: any) => string;
52
73
  export default class UtilsServer {
53
74
  static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
@@ -55,6 +76,27 @@ export default class UtilsServer {
55
76
  static hashPassword: (password: string) => string;
56
77
  static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
57
78
  static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
58
- static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
79
+ static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => (({
80
+ id?: string | number | undefined;
81
+ key: string;
82
+ required?: boolean | undefined;
83
+ } & {
84
+ type: "string" | "number" | "boolean" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip";
85
+ children?: undefined;
86
+ }) | ({
87
+ id?: string | number | undefined;
88
+ key: string;
89
+ required?: boolean | undefined;
90
+ } & {
91
+ type: "object";
92
+ children: Schema;
93
+ }) | ({
94
+ id?: string | number | undefined;
95
+ key: string;
96
+ required?: boolean | undefined;
97
+ } & {
98
+ type: "array";
99
+ children: "string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip" | Schema | ("string" | "number" | "boolean" | "object" | "id" | "url" | "html" | "table" | "email" | "date" | "password" | "ip")[];
100
+ }))[];
59
101
  static hashObject: (obj: any) => string;
60
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.27",
3
+ "version": "1.0.0-rc.28",
4
4
  "author": {
5
5
  "name": "Karim Amahtil",
6
6
  "email": "karim.amahtil@gmail.com"