inibase 1.0.0-rc.76 → 1.0.0-rc.78

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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import "dotenv/config";
3
3
  import { readFileSync } from "node:fs";
4
- import { basename, join } from "node:path";
4
+ import { join } from "node:path";
5
5
  import { createInterface } from "node:readline/promises";
6
6
  import { parseArgs } from "node:util";
7
7
  import Inison from "inison";
@@ -12,10 +12,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`;
14
14
  const textMagenta = (input) => `\u001b[1;35m${input}\u001b[0m`;
15
- let { path, version } = parseArgs({
15
+ let { path, version, table } = parseArgs({
16
16
  options: {
17
17
  path: { type: "string", short: "p" },
18
18
  version: { type: "boolean", short: "v" },
19
+ table: { type: "string", short: "t" },
19
20
  },
20
21
  }).values;
21
22
  if (version) {
@@ -30,16 +31,15 @@ const rl = createInterface({
30
31
  const setPath = async (firstTime) => {
31
32
  if (!path)
32
33
  path = await rl.question(firstTime ? "Database path: " : "Please type a valid database path: ");
33
- if (!path || !(await isExists(basename(path))))
34
+ if (!path || !(await isExists(path)))
34
35
  await setPath();
35
36
  };
36
37
  console.clear();
37
38
  await setPath(true);
38
- const db = new Inibase(basename(path));
39
+ const db = new Inibase(path);
39
40
  process.stdout.write("\u001b[3J\u001b[2J\u001b[1J");
40
41
  console.clear();
41
42
  rl.prompt();
42
- let table;
43
43
  rl.on("line", async (input) => {
44
44
  const splitedInput = input
45
45
  .trim()
@@ -70,6 +70,7 @@ rl.on("line", async (input) => {
70
70
  ${textMagenta("--page")} | ${textMagenta("-p")} number?
71
71
  ${textMagenta("--per-page")} | ${textMagenta("-l")} number?
72
72
  ${textMagenta("--columns")} | ${textMagenta("-c")} columnName[]?
73
+ ${textMagenta("--sort")} | ${textMagenta("-s")} (string|string[]|Inison.stringify(sortObject))?
73
74
  ${textMagenta("--data")} | ${textMagenta("-d")} Inison.stringify(Data) ${textRed("* POST & PUT")}`);
74
75
  break;
75
76
  }
package/dist/file.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import type { ComparisonOperator, FieldType, Schema } from "./index.js";
3
2
  export declare const lock: (folderPath: string, prefix?: string) => Promise<void>;
4
3
  export declare const unlock: (folderPath: string, prefix?: string) => Promise<void>;
@@ -107,11 +106,7 @@ export declare const remove: (filePath: string, linesToDelete: number | number[]
107
106
  *
108
107
  * Note: Decodes each line for comparison and can handle complex queries with multiple conditions.
109
108
  */
110
- export declare const search: (filePath: string, operator: ComparisonOperator | ComparisonOperator[], comparedAtValue: string | number | boolean | null | (string | number | boolean | null)[], logicalOperator?: "and" | "or", fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | Schema, limit?: number, offset?: number, readWholeFile?: boolean, secretKey?: string | Buffer) => Promise<[
111
- Record<number, string | number | boolean | null | (string | number | boolean | null)[]> | null,
112
- number,
113
- Set<number> | null
114
- ]>;
109
+ export declare const search: (filePath: string, operator: ComparisonOperator | ComparisonOperator[], comparedAtValue: string | number | boolean | null | (string | number | boolean | null)[], logicalOperator?: "and" | "or", 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]>;
115
110
  /**
116
111
  * Asynchronously counts the number of lines in a file.
117
112
  *
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import "dotenv/config";
3
2
  export interface Data {
4
3
  id?: number | string;
package/dist/index.js CHANGED
@@ -222,30 +222,32 @@ export default class Inibase {
222
222
  const schemaFile = await readFile(tableSchemaPath, "utf8");
223
223
  if (!schemaFile)
224
224
  return undefined;
225
- const schema = JSON.parse(schemaFile), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
226
- if (!encodeIDs)
227
- return schema;
228
- return [
225
+ let schema = JSON.parse(schemaFile);
226
+ const lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
227
+ schema = [
229
228
  {
230
- id: UtilsServer.encodeID(0, this.salt),
229
+ id: 0,
231
230
  key: "id",
232
231
  type: "id",
233
232
  required: true,
234
233
  },
235
- ...UtilsServer.encodeSchemaID(schema, this.salt),
234
+ ...schema,
236
235
  {
237
- id: UtilsServer.encodeID(lastIdNumber + 1, this.salt),
236
+ id: lastIdNumber + 1,
238
237
  key: "createdAt",
239
238
  type: "date",
240
239
  required: true,
241
240
  },
242
241
  {
243
- id: UtilsServer.encodeID(lastIdNumber + 2, this.salt),
242
+ id: lastIdNumber + 2,
244
243
  key: "updatedAt",
245
244
  type: "date",
246
245
  required: false,
247
246
  },
248
247
  ];
248
+ if (!encodeIDs)
249
+ return schema;
250
+ return UtilsServer.encodeSchemaID(schema, this.salt);
249
251
  }
250
252
  async throwErrorIfTableEmpty(tableName) {
251
253
  const table = await this.getTable(tableName);
@@ -820,7 +822,7 @@ export default class Inibase {
820
822
  (Utils.isObject(where) && !Object.keys(where).length)))
821
823
  where = undefined;
822
824
  if (options.sort) {
823
- let sortArray, isLineNumbers = true, keepItems = [];
825
+ let sortArray, awkCommand = "";
824
826
  if (Utils.isObject(options.sort) && !Array.isArray(options.sort)) {
825
827
  // {name: "ASC", age: "DESC"}
826
828
  sortArray = Object.entries(options.sort).map(([key, value]) => [
@@ -838,16 +840,17 @@ export default class Inibase {
838
840
  cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
839
841
  if (where) {
840
842
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
841
- keepItems = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
842
- isLineNumbers = false;
843
- if (!keepItems.length)
843
+ if (!lineNumbers.length)
844
844
  throw this.throwError("NO_RESULTS", tableName);
845
- keepItems = keepItems.slice((options.page - 1) * options.perPage, options.page * options.perPage);
845
+ const itemsIDs = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
846
+ awkCommand = `awk '${itemsIDs.map((id) => `$1 == ${id}`).join(" || ")}'`;
846
847
  }
847
- if (!keepItems.length)
848
- keepItems = Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
848
+ else
849
+ awkCommand = `awk '${Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
849
850
  index +
850
- 1);
851
+ 1)
852
+ .map((lineNumber) => `NR==${lineNumber}`)
853
+ .join(" || ")}'`;
851
854
  const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}${this.getFileExtension(tableName)}`));
852
855
  for await (const path of filesPathes.slice(1))
853
856
  if (!(await File.isExists(path)))
@@ -867,15 +870,11 @@ export default class Inibase {
867
870
  })
868
871
  .join(" ");
869
872
  const sortCommand = `sort ${sortColumns} -T=${join(tablePath, ".tmp")}`;
870
- // Construct the awk command to keep only the specified lines after sorting
871
- const awkCommand = isLineNumbers
872
- ? `awk '${keepItems.map((lineNumber) => `NR==${lineNumber}`).join(" || ")}'`
873
- : `awk '${keepItems.map((id) => `$1 ~ /^${id} */`).join(" || ")}'`;
874
873
  try {
875
874
  if (cacheKey)
876
875
  await File.lock(join(tablePath, ".tmp"), cacheKey);
877
876
  // Combine && Execute the commands synchronously
878
- const lines = (await UtilsServer.exec(this.tables[tableName].config.cache
877
+ let lines = (await UtilsServer.exec(this.tables[tableName].config.cache
879
878
  ? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
880
879
  ? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
881
880
  : `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
@@ -884,6 +883,12 @@ export default class Inibase {
884
883
  })).stdout
885
884
  .trim()
886
885
  .split("\n");
886
+ if (where)
887
+ lines = lines.slice((options.page - 1) * options.perPage, options.page * options.perPage);
888
+ else if (!this.totalItems[`${tableName}-*`])
889
+ this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
890
+ if (!lines.length)
891
+ return null;
887
892
  // Parse the result and extract the specified lines
888
893
  const outputArray = lines.map((line) => {
889
894
  const splitedFileColumns = line.split("\t"); // Assuming tab-separated columns
@@ -914,11 +919,14 @@ export default class Inibase {
914
919
  RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
915
920
  index +
916
921
  1), options));
917
- if (await File.isExists(join(tablePath, ".cache", ".pagination")))
918
- this.totalItems[`${tableName}-*`] = Number((await readFile(join(tablePath, ".cache", ".pagination"), "utf8")).split(",")[1]);
922
+ if (await File.isExists(join(tablePath, ".cache", ".pagination"))) {
923
+ if (!this.totalItems[`${tableName}-*`])
924
+ this.totalItems[`${tableName}-*`] = Number((await readFile(join(tablePath, ".cache", ".pagination"), "utf8")).split(",")[1]);
925
+ }
919
926
  else {
920
927
  const lastId = Number(Object.keys((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), -1, "number", undefined, this.salt, true))?.[0] ?? 0));
921
- this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
928
+ if (!this.totalItems[`${tableName}-*`])
929
+ this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
922
930
  await writeFile(join(tablePath, ".cache", ".pagination"), `${lastId},${this.totalItems[`${tableName}-*`]}`);
923
931
  }
924
932
  }
@@ -928,12 +936,12 @@ export default class Inibase {
928
936
  let lineNumbers = where;
929
937
  if (!Array.isArray(lineNumbers))
930
938
  lineNumbers = [lineNumbers];
939
+ if (!this.totalItems[`${tableName}-*`])
940
+ this.totalItems[`${tableName}-*`] = lineNumbers.length;
931
941
  // useless
932
942
  if (onlyLinesNumbers)
933
943
  return lineNumbers;
934
944
  RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, lineNumbers, options)) ?? {});
935
- if (!this.totalItems[`${tableName}-*`])
936
- this.totalItems[`${tableName}-*`] = lineNumbers.length;
937
945
  if (RETURN?.length && !Array.isArray(where))
938
946
  RETURN = RETURN[0];
939
947
  }
@@ -945,6 +953,8 @@ export default class Inibase {
945
953
  const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension(tableName)}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, !this.totalItems[`${tableName}-*`], this.salt);
946
954
  if (!lineNumbers)
947
955
  throw this.throwError("NO_RESULTS", tableName);
956
+ if (!this.totalItems[`${tableName}-*`])
957
+ this.totalItems[`${tableName}-*`] = countItems;
948
958
  if (onlyLinesNumbers)
949
959
  return Object.keys(lineNumbers).length
950
960
  ? Object.keys(lineNumbers).map(Number)
@@ -955,8 +965,6 @@ export default class Inibase {
955
965
  options.columns = undefined;
956
966
  }
957
967
  RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
958
- if (!this.totalItems[`${tableName}-*`])
959
- this.totalItems[`${tableName}-*`] = countItems;
960
968
  if (RETURN?.length && !Array.isArray(where))
961
969
  RETURN = RETURN[0];
962
970
  }
@@ -968,7 +976,8 @@ export default class Inibase {
968
976
  if (this.tables[tableName].config.cache &&
969
977
  (await File.isExists(cachedFilePath))) {
970
978
  const cachedItems = (await readFile(cachedFilePath, "utf8")).split(",");
971
- this.totalItems[`${tableName}-*`] = cachedItems.length;
979
+ if (!this.totalItems[`${tableName}-*`])
980
+ this.totalItems[`${tableName}-*`] = cachedItems.length;
972
981
  if (onlyLinesNumbers)
973
982
  return cachedItems.map(Number);
974
983
  return this.get(tableName, cachedItems
@@ -978,8 +987,10 @@ export default class Inibase {
978
987
  let linesNumbers = null;
979
988
  [RETURN, linesNumbers] = await this.applyCriteria(tableName, schema, options, where);
980
989
  if (RETURN && linesNumbers) {
990
+ if (!this.totalItems[`${tableName}-*`])
991
+ this.totalItems[`${tableName}-*`] = linesNumbers.size;
981
992
  if (onlyLinesNumbers)
982
- return Object.keys(RETURN).map(Number);
993
+ return Array.from(linesNumbers);
983
994
  const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]), alreadyExistsColumnsIDs = Utils.flattenSchema(schema)
984
995
  .filter(({ key }) => alreadyExistsColumns.includes(key))
985
996
  .map(({ id }) => id);
@@ -1028,7 +1039,8 @@ export default class Inibase {
1028
1039
  .map(Number);
1029
1040
  else {
1030
1041
  lastId = Number(Object.keys((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), -1, "number", undefined, this.salt, true))?.[0] ?? 0));
1031
- this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
1042
+ if (!this.totalItems[`${tableName}-*`])
1043
+ this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
1032
1044
  }
1033
1045
  }
1034
1046
  else
@@ -1,6 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- /// <reference types="node" resolution-mode="require"/>
4
1
  import { exec as execAsync, execFile as execFileAsync } from "node:child_process";
5
2
  import { gunzip as gunzipAsync, gzip as gzipAsync } from "node:zlib";
6
3
  import type { ComparisonOperator, Field, FieldType, Schema } from "./index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.76",
3
+ "version": "1.0.0-rc.78",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Karim Amahtil",