inibase 1.0.0-rc.57 → 1.0.0-rc.59

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/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import "dotenv/config";
1
2
  import { unlink, rename, mkdir, readdir } from "node:fs/promises";
2
3
  import { existsSync, appendFileSync, readFileSync } from "node:fs";
3
4
  import { join, parse } from "node:path";
@@ -13,8 +14,8 @@ export default class Inibase {
13
14
  database;
14
15
  table;
15
16
  pageInfo;
17
+ fileExtension = ".txt";
16
18
  checkIFunique;
17
- isThreadEnabled = false;
18
19
  totalItems;
19
20
  salt;
20
21
  constructor(database, mainFolder = ".", _table = null, _totalItems = {}, _pageInfo = {}, _isThreadEnabled = false) {
@@ -23,7 +24,6 @@ export default class Inibase {
23
24
  this.table = _table;
24
25
  this.totalItems = _totalItems;
25
26
  this.pageInfo = _pageInfo;
26
- this.isThreadEnabled = _isThreadEnabled;
27
27
  this.checkIFunique = {};
28
28
  if (!process.env.INIBASE_SECRET) {
29
29
  if (existsSync(".env") &&
@@ -34,6 +34,19 @@ export default class Inibase {
34
34
  }
35
35
  else
36
36
  this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
37
+ // try {
38
+ // if (Config.isCompressionEnabled)
39
+ // execSync(
40
+ // `gzip -r ${join(this.folder, this.database)}/*/*.txt 2>/dev/null`,
41
+ // );
42
+ // else
43
+ // execSync(
44
+ // `gunzip -r ${join(
45
+ // this.folder,
46
+ // this.database,
47
+ // )}/*/*.txt.gz 2>/dev/null`,
48
+ // );
49
+ // } catch {}
37
50
  }
38
51
  throwError(code, variable, language = "en") {
39
52
  const errorMessages = {
@@ -61,6 +74,15 @@ export default class Inibase {
61
74
  : errorMessage.replaceAll("{variable}", `'${variable.toString()}'`)
62
75
  : errorMessage.replaceAll("{variable}", ""));
63
76
  }
77
+ getFileExtension = () => {
78
+ let mainExtension = this.fileExtension;
79
+ // TODO: ADD ENCRYPTION
80
+ // if(Config.isEncryptionEnabled)
81
+ // mainExtension += ".enc"
82
+ if (Config.isCompressionEnabled)
83
+ mainExtension += ".gz";
84
+ return mainExtension;
85
+ };
64
86
  _schemaToIdsPath = (schema, prefix = "") => {
65
87
  const RETURN = {};
66
88
  for (const field of schema)
@@ -70,7 +92,7 @@ export default class Inibase {
70
92
  Utils.deepMerge(RETURN, this._schemaToIdsPath(field.children, `${(prefix ?? "") + field.key}.`));
71
93
  }
72
94
  else if (field.id)
73
- RETURN[field.id] = `${(prefix ?? "") + field.key}.inib`;
95
+ RETURN[field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension()}`;
74
96
  return RETURN;
75
97
  };
76
98
  async setTableSchema(tableName, schema) {
@@ -140,7 +162,7 @@ export default class Inibase {
140
162
  schema = await this.getTableSchema(tableName);
141
163
  if (!schema)
142
164
  throw this.throwError("NO_SCHEMA", tableName);
143
- if (!(await File.isExists(join(tablePath, "id.inib"))))
165
+ if (!(await File.isExists(join(tablePath, `id${this.getFileExtension()}`))))
144
166
  throw this.throwError("NO_ITEMS", tableName);
145
167
  return schema;
146
168
  }
@@ -268,7 +290,7 @@ export default class Inibase {
268
290
  const field = Utils.getField(key, schema);
269
291
  if (!field)
270
292
  continue;
271
- const [searchResult, totalLines] = await File.search(join(tablePath, `${key}.inib`), Array.isArray(values) ? "=" : "[]", values, undefined, field.type, field.children, 1, undefined, false, this.salt);
293
+ const [searchResult, totalLines] = await File.search(join(tablePath, `${key}${this.getFileExtension()}`), Array.isArray(values) ? "=" : "[]", values, undefined, field.type, field.children, 1, undefined, false, this.salt);
272
294
  if (searchResult && totalLines > 0)
273
295
  throw this.throwError("FIELD_UNIQUE", [
274
296
  field.key,
@@ -357,7 +379,7 @@ export default class Inibase {
357
379
  _addPathToKeys = (obj, path) => {
358
380
  const newObject = {};
359
381
  for (const key in obj)
360
- newObject[join(path, `${key}.inib`)] = obj[key];
382
+ newObject[join(path, `${key}${this.getFileExtension()}`)] = obj[key];
361
383
  return newObject;
362
384
  };
363
385
  joinPathesContents(mainPath, data) {
@@ -407,7 +429,7 @@ export default class Inibase {
407
429
  async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
408
430
  const tablePath = join(this.folder, this.database, tableName);
409
431
  let RETURN = {};
410
- await Promise.all(schema.map(async (field) => {
432
+ for await (const field of schema) {
411
433
  if ((field.type === "array" ||
412
434
  (Array.isArray(field.type) && field.type.includes("array"))) &&
413
435
  field.children) {
@@ -415,82 +437,86 @@ export default class Inibase {
415
437
  if (field.children.filter((children) => children.type === "array" &&
416
438
  Utils.isArrayOfObjects(children.children)).length) {
417
439
  // one of children has array field type and has children array of object = Schema
418
- for (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children.filter((children) => children.type === "array" &&
419
- Utils.isArrayOfObjects(children.children)), linesNumber, options, `${(prefix ?? "") + field.key}.`)) ?? {}))
420
- this._getItemsFromSchemaHelper(RETURN, item, index, field);
440
+ const childItems = await this.getItemsFromSchema(tableName, field.children.filter((children) => children.type === "array" &&
441
+ Utils.isArrayOfObjects(children.children)), linesNumber, options, `${(prefix ?? "") + field.key}.`);
442
+ if (childItems)
443
+ for (const [index, item] of Object.entries(childItems))
444
+ this._getItemsFromSchemaHelper(RETURN, item, index, field);
421
445
  field.children = field.children.filter((children) => children.type !== "array" ||
422
446
  !Utils.isArrayOfObjects(children.children));
423
447
  }
424
- for (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`)) ?? {})) {
425
- if (!RETURN[index])
426
- RETURN[index] = {};
427
- if (Utils.isObject(item)) {
428
- if (!Utils.isArrayOfNulls(Object.values(item))) {
429
- if (RETURN[index][field.key])
430
- Object.entries(item).forEach(([key, value], _index) => {
431
- for (let _index = 0; _index < value.length; _index++)
432
- if (RETURN[index][field.key][_index])
433
- Object.assign(RETURN[index][field.key][_index], {
434
- [key]: value[_index],
435
- });
436
- else
437
- RETURN[index][field.key][_index] = {
438
- [key]: value[_index],
439
- };
440
- });
441
- else if (Object.values(item).every((_i) => Utils.isArrayOfArrays(_i) || Array.isArray(_i)) &&
442
- prefix)
443
- RETURN[index][field.key] = item;
444
- else {
445
- RETURN[index][field.key] = [];
446
- Object.entries(item).forEach(([key, value], _ind) => {
447
- if (!Array.isArray(value)) {
448
- RETURN[index][field.key][_ind] = {};
449
- RETURN[index][field.key][_ind][key] = value;
450
- }
451
- else
452
- for (let _i = 0; _i < value.length; _i++) {
453
- if (value[_i] === null ||
454
- (Array.isArray(value[_i]) &&
455
- Utils.isArrayOfNulls(value[_i])))
456
- continue;
457
- if (!RETURN[index][field.key][_i])
458
- RETURN[index][field.key][_i] = {};
459
- RETURN[index][field.key][_i][key] = value[_i];
448
+ const fieldItems = await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`);
449
+ if (fieldItems)
450
+ for (const [index, item] of Object.entries(fieldItems)) {
451
+ if (!RETURN[index])
452
+ RETURN[index] = {};
453
+ if (Utils.isObject(item)) {
454
+ if (!Utils.isArrayOfNulls(Object.values(item))) {
455
+ if (RETURN[index][field.key])
456
+ Object.entries(item).forEach(([key, value], _index) => {
457
+ for (let _index = 0; _index < value.length; _index++)
458
+ if (RETURN[index][field.key][_index])
459
+ Object.assign(RETURN[index][field.key][_index], {
460
+ [key]: value[_index],
461
+ });
462
+ else
463
+ RETURN[index][field.key][_index] = {
464
+ [key]: value[_index],
465
+ };
466
+ });
467
+ else if (Object.values(item).every((_i) => Utils.isArrayOfArrays(_i) || Array.isArray(_i)) &&
468
+ prefix)
469
+ RETURN[index][field.key] = item;
470
+ else {
471
+ RETURN[index][field.key] = [];
472
+ Object.entries(item).forEach(([key, value], _ind) => {
473
+ if (!Array.isArray(value)) {
474
+ RETURN[index][field.key][_ind] = {};
475
+ RETURN[index][field.key][_ind][key] = value;
460
476
  }
461
- });
477
+ else
478
+ for (let _i = 0; _i < value.length; _i++) {
479
+ if (value[_i] === null ||
480
+ (Array.isArray(value[_i]) &&
481
+ Utils.isArrayOfNulls(value[_i])))
482
+ continue;
483
+ if (!RETURN[index][field.key][_i])
484
+ RETURN[index][field.key][_i] = {};
485
+ RETURN[index][field.key][_i][key] = value[_i];
486
+ }
487
+ });
488
+ }
462
489
  }
490
+ else
491
+ RETURN[index][field.key] = null;
463
492
  }
464
493
  else
465
- RETURN[index][field.key] = null;
494
+ RETURN[index][field.key] = item;
466
495
  }
467
- else
468
- RETURN[index][field.key] = item;
469
- }
470
496
  }
471
497
  else if (field.children === "table" ||
472
498
  (Array.isArray(field.type) && field.type.includes("table")) ||
473
499
  (Array.isArray(field.children) && field.children.includes("table"))) {
474
500
  if (field.table &&
475
501
  (await File.isExists(join(this.folder, this.database, field.table))) &&
476
- (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.inib`)))) {
502
+ (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`)))) {
477
503
  if (options.columns)
478
504
  options.columns = options.columns
479
505
  .filter((column) => column.includes(`${field.key}.`))
480
506
  .map((column) => column.replace(`${field.key}.`, ""));
481
- const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.inib`), linesNumber, field.type, field.children, this.salt);
507
+ const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
482
508
  if (items)
483
- await Promise.allSettled(Object.entries(items).map(async ([index, item]) => {
509
+ for await (const [index, item] of Object.entries(items)) {
484
510
  if (!RETURN[index])
485
511
  RETURN[index] = {};
486
512
  RETURN[index][field.key] = item
487
513
  ? await this.get(field.table, item, options)
488
514
  : this.getDefaultValue(field);
489
- }));
515
+ }
490
516
  }
491
517
  }
492
- else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.inib`))) {
493
- const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.inib`), linesNumber, field.type, field.children, this.salt);
518
+ else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`))) {
519
+ const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
494
520
  if (items)
495
521
  for (const [index, item] of Object.entries(items)) {
496
522
  if (!RETURN[index])
@@ -500,40 +526,42 @@ export default class Inibase {
500
526
  }
501
527
  }
502
528
  else if (field.type === "object") {
503
- for await (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`)) ?? {})) {
504
- if (!RETURN[index])
505
- RETURN[index] = {};
506
- if (Utils.isObject(item)) {
507
- if (!Object.values(item).every((i) => i === null))
508
- RETURN[index][field.key] = item;
529
+ const fieldItems = await this.getItemsFromSchema(tableName, field.children, linesNumber, options, `${(prefix ?? "") + field.key}.`);
530
+ if (fieldItems)
531
+ for (const [index, item] of Object.entries(fieldItems)) {
532
+ if (!RETURN[index])
533
+ RETURN[index] = {};
534
+ if (Utils.isObject(item)) {
535
+ if (!Object.values(item).every((i) => i === null))
536
+ RETURN[index][field.key] = item;
537
+ else
538
+ RETURN[index][field.key] = null;
539
+ }
509
540
  else
510
541
  RETURN[index][field.key] = null;
511
542
  }
512
- else
513
- RETURN[index][field.key] = null;
514
- }
515
543
  }
516
544
  else if (field.type === "table") {
517
545
  if (field.table &&
518
546
  (await File.isExists(join(this.folder, this.database, field.table))) &&
519
- (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.inib`)))) {
547
+ (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`)))) {
520
548
  if (options.columns)
521
549
  options.columns = options.columns
522
550
  .filter((column) => column.includes(`${field.key}.`))
523
551
  .map((column) => column.replace(`${field.key}.`, ""));
524
- const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.inib`), linesNumber, "number", undefined, this.salt);
552
+ const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, "number", undefined, this.salt);
525
553
  if (items)
526
- await Promise.allSettled(Object.entries(items).map(async ([index, item]) => {
554
+ for await (const [index, item] of Object.entries(items)) {
527
555
  if (!RETURN[index])
528
556
  RETURN[index] = {};
529
557
  RETURN[index][field.key] = item
530
558
  ? await this.get(field.table, item, options)
531
559
  : this.getDefaultValue(field);
532
- }));
560
+ }
533
561
  }
534
562
  }
535
- else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}.inib`))) {
536
- const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}.inib`), linesNumber, field.type, field.children, this.salt);
563
+ else if (await File.isExists(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`))) {
564
+ const items = await File.get(join(tablePath, `${(prefix ?? "") + field.key}${this.getFileExtension()}`), linesNumber, field.type, field.children, this.salt);
537
565
  if (items)
538
566
  for (const [index, item] of Object.entries(items)) {
539
567
  if (!RETURN[index])
@@ -546,7 +574,7 @@ export default class Inibase {
546
574
  { ...data, [field.key]: this.getDefaultValue(field) },
547
575
  ]));
548
576
  }
549
- }));
577
+ }
550
578
  return RETURN;
551
579
  }
552
580
  async applyCriteria(tableName, schema, options, criteria, allTrue) {
@@ -634,7 +662,7 @@ export default class Inibase {
634
662
  searchOperator = "=";
635
663
  searchComparedAtValue = value;
636
664
  }
637
- const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}.inib`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, options.page - 1 * options.perPage + 1, true, this.salt);
665
+ const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension()}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, options.page - 1 * options.perPage + 1, true, this.salt);
638
666
  if (searchResult) {
639
667
  RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
640
668
  id,
@@ -679,7 +707,7 @@ export default class Inibase {
679
707
  }
680
708
  async clearCache(tablePath) {
681
709
  await Promise.all((await readdir(join(tablePath, ".cache")))
682
- ?.filter((fileName) => fileName !== "pagination.inib")
710
+ ?.filter((fileName) => fileName !== `pagination${this.fileExtension}`)
683
711
  .map(async (file) => unlink(join(tablePath, ".cache", file))));
684
712
  }
685
713
  async get(tableName, where, options = {
@@ -713,16 +741,14 @@ export default class Inibase {
713
741
  RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
714
742
  index +
715
743
  1), options));
716
- if (Config.isCacheEnabled &&
717
- (await File.isExists(join(tablePath, ".cache", "pagination.inib"))))
718
- this.totalItems[`${tableName}-*`] = Number((await File.read(join(tablePath, ".cache", "pagination.inib"), true)).split(",")[1]);
744
+ if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
745
+ this.totalItems[`${tableName}-*`] = Number((await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true)).split(",")[1]);
719
746
  else {
720
- let [lastId, totalItems] = await File.get(join(tablePath, "id.inib"), -1, "number", undefined, this.salt, true);
747
+ let [lastId, totalItems] = await File.get(join(tablePath, `id${this.getFileExtension()}`), -1, "number", undefined, this.salt, true);
721
748
  if (lastId)
722
749
  lastId = Number(Object.keys(lastId)?.[0] ?? 0);
723
750
  this.totalItems[`${tableName}-*`] = totalItems;
724
- if (Config.isCacheEnabled)
725
- await File.write(join(tablePath, ".cache", "pagination.inib"), `${lastId},${totalItems}`, true);
751
+ await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems}`, true);
726
752
  }
727
753
  }
728
754
  else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
@@ -745,7 +771,7 @@ export default class Inibase {
745
771
  let Ids = where;
746
772
  if (!Array.isArray(Ids))
747
773
  Ids = [Ids];
748
- const [lineNumbers, countItems] = await File.search(join(tablePath, "id.inib"), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, !this.totalItems[`${tableName}-*`], this.salt);
774
+ const [lineNumbers, countItems] = await File.search(join(tablePath, `id${this.getFileExtension()}`), "[]", Ids.map((id) => Utils.isNumber(id) ? Number(id) : UtilsServer.decodeID(id, this.salt)), undefined, "number", undefined, Ids.length, 0, !this.totalItems[`${tableName}-*`], this.salt);
749
775
  if (!lineNumbers)
750
776
  throw this.throwError("NO_RESULTS", tableName);
751
777
  if (onlyLinesNumbers)
@@ -762,7 +788,7 @@ export default class Inibase {
762
788
  let cachedFilePath = "";
763
789
  // Criteria
764
790
  if (Config.isCacheEnabled)
765
- cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}.inib`);
791
+ cachedFilePath = join(tablePath, ".cache", `${UtilsServer.hashString(inspect(where, { sorted: true }))}${this.fileExtension}`);
766
792
  if (Config.isCacheEnabled && (await File.isExists(cachedFilePath))) {
767
793
  const cachedItems = (await File.read(cachedFilePath, true)).split(",");
768
794
  this.totalItems[`${tableName}-*`] = cachedItems.length;
@@ -815,15 +841,14 @@ export default class Inibase {
815
841
  let lastId = 0, totalItems = 0, renameList = [];
816
842
  try {
817
843
  await File.lock(join(tablePath, ".tmp"), keys);
818
- if (await File.isExists(join(tablePath, "id.inib"))) {
819
- if (Config.isCacheEnabled &&
820
- (await File.isExists(join(tablePath, ".cache", "pagination.inib"))))
821
- [lastId, totalItems] = (await File.read(join(tablePath, ".cache", "pagination.inib"), true))
844
+ if (await File.isExists(join(tablePath, `id${this.getFileExtension()}`))) {
845
+ if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
846
+ [lastId, totalItems] = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
822
847
  .split(",")
823
848
  .map(Number);
824
849
  else {
825
850
  let lastIdObj = null;
826
- [lastIdObj, totalItems] = await File.get(join(tablePath, "id.inib"), -1, "number", undefined, this.salt, true);
851
+ [lastIdObj, totalItems] = await File.get(join(tablePath, `id${this.getFileExtension()}`), -1, "number", undefined, this.salt, true);
827
852
  if (lastIdObj)
828
853
  lastId = Number(Object.keys(lastIdObj)?.[0] ?? 0);
829
854
  }
@@ -852,10 +877,9 @@ export default class Inibase {
852
877
  await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
853
878
  renameList = [];
854
879
  totalItems += Array.isArray(RETURN) ? RETURN.length : 1;
855
- if (Config.isCacheEnabled) {
880
+ if (Config.isCacheEnabled)
856
881
  await this.clearCache(tablePath);
857
- await File.write(join(tablePath, ".cache", "pagination.inib"), `${lastId},${totalItems}`, true);
858
- }
882
+ await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems}`, true);
859
883
  if (returnPostedData)
860
884
  return this.get(tableName, Config.isReverseEnabled
861
885
  ? Array.isArray(RETURN)
@@ -895,13 +919,12 @@ export default class Inibase {
895
919
  return this.put(tableName, data, data.id);
896
920
  }
897
921
  let totalItems;
898
- if (Config.isCacheEnabled &&
899
- (await File.isExists(join(tablePath, ".cache", "pagination.inib"))))
900
- totalItems = (await File.read(join(tablePath, ".cache", "pagination.inib"), true))
922
+ if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`)))
923
+ totalItems = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
901
924
  .split(",")
902
925
  .map(Number)[1];
903
926
  else
904
- totalItems = await File.count(join(tablePath, "id.inib"));
927
+ totalItems = await File.count(join(tablePath, `id${this.getFileExtension()}`));
905
928
  const pathesContents = this.joinPathesContents(tablePath, {
906
929
  ...(({ id, ...restOfData }) => restOfData)(data),
907
930
  updatedAt: Date.now(),
@@ -998,26 +1021,23 @@ export default class Inibase {
998
1021
  if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
999
1022
  Utils.isNumber(where)) {
1000
1023
  // "where" in this case, is the line(s) number(s) and not id(s)
1001
- const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(".inib"));
1024
+ const files = (await readdir(tablePath))?.filter((fileName) => fileName.endsWith(this.getFileExtension()));
1002
1025
  if (files.length) {
1003
- if (!_id)
1004
- _id = Object.entries((await File.get(join(tablePath, "id.inib"), where, "number", undefined, this.salt)) ?? {}).map(([_, id]) => UtilsServer.encodeID(id, this.salt));
1005
- if (!_id.length)
1006
- throw this.throwError("NO_RESULTS", tableName);
1007
1026
  try {
1008
1027
  await File.lock(join(tablePath, ".tmp"));
1009
1028
  await Promise.all(files.map(async (file) => renameList.push(await File.remove(join(tablePath, file), where))));
1010
1029
  await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
1011
- if (Config.isCacheEnabled) {
1030
+ if (Config.isCacheEnabled)
1012
1031
  await this.clearCache(tablePath);
1013
- if (await File.isExists(join(tablePath, ".cache", "pagination.inib"))) {
1014
- const [lastId, totalItems] = (await File.read(join(tablePath, ".cache", "pagination.inib"), true))
1015
- .split(",")
1016
- .map(Number);
1017
- await File.write(join(tablePath, ".cache", "pagination.inib"), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`, true);
1018
- }
1032
+ if (await File.isExists(join(tablePath, ".cache", `pagination${this.fileExtension}`))) {
1033
+ const [lastId, totalItems] = (await File.read(join(tablePath, ".cache", `pagination${this.fileExtension}`), true))
1034
+ .split(",")
1035
+ .map(Number);
1036
+ await File.write(join(tablePath, ".cache", `pagination${this.fileExtension}`), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`, true);
1019
1037
  }
1020
- return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
1038
+ if (_id)
1039
+ return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
1040
+ return where;
1021
1041
  }
1022
1042
  finally {
1023
1043
  if (renameList.length)
@@ -1040,7 +1060,7 @@ export default class Inibase {
1040
1060
  if (!Array.isArray(columns))
1041
1061
  columns = [columns];
1042
1062
  for await (const column of columns) {
1043
- const columnPath = join(tablePath, `${column}.inib`);
1063
+ const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
1044
1064
  if (await File.isExists(columnPath)) {
1045
1065
  if (where) {
1046
1066
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
@@ -1060,7 +1080,7 @@ export default class Inibase {
1060
1080
  if (!Array.isArray(columns))
1061
1081
  columns = [columns];
1062
1082
  for await (const column of columns) {
1063
- const columnPath = join(tablePath, `${column}.inib`);
1083
+ const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
1064
1084
  if (await File.isExists(columnPath)) {
1065
1085
  if (where) {
1066
1086
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
@@ -1080,7 +1100,7 @@ export default class Inibase {
1080
1100
  if (!Array.isArray(columns))
1081
1101
  columns = [columns];
1082
1102
  for await (const column of columns) {
1083
- const columnPath = join(tablePath, `${column}.inib`);
1103
+ const columnPath = join(tablePath, `${column}${this.getFileExtension()}`);
1084
1104
  if (await File.isExists(columnPath)) {
1085
1105
  if (where) {
1086
1106
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
@@ -1098,7 +1118,6 @@ export default class Inibase {
1098
1118
  page: 1,
1099
1119
  perPage: 15,
1100
1120
  }) {
1101
- // TO-DO: Cache Results based on "Columns and Sort Direction"
1102
1121
  const tablePath = join(this.folder, this.database, tableName), schema = await this.getSchemaWhenTableNotEmpty(tableName);
1103
1122
  // Default values for page and perPage
1104
1123
  options.page = options.page || 1;
@@ -1122,7 +1141,7 @@ export default class Inibase {
1122
1141
  cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
1123
1142
  if (where) {
1124
1143
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true, schema);
1125
- keepItems = Object.values((await File.get(join(tablePath, "id.inib"), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
1144
+ keepItems = Object.values((await File.get(join(tablePath, `id${this.getFileExtension()}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
1126
1145
  isLineNumbers = false;
1127
1146
  if (!keepItems.length)
1128
1147
  throw this.throwError("NO_RESULTS", tableName);
@@ -1132,7 +1151,7 @@ export default class Inibase {
1132
1151
  keepItems = Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
1133
1152
  index +
1134
1153
  1);
1135
- const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}.inib`));
1154
+ const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}${this.getFileExtension()}`));
1136
1155
  // Construct the paste command to merge files and filter lines by IDs
1137
1156
  const pasteCommand = `paste ${filesPathes.join(" ")}`;
1138
1157
  // Construct the sort command dynamically based on the number of files for sorting
@@ -1157,10 +1176,10 @@ export default class Inibase {
1157
1176
  await File.lock(join(tablePath, ".tmp"), cacheKey);
1158
1177
  // Combine the commands
1159
1178
  // Execute the command synchronously
1160
- const { stdout, stderr } = await UtilsServer.exec(Config.isCacheEnabled
1161
- ? (await File.isExists(join(tablePath, ".cache", `${cacheKey}.inib`)))
1162
- ? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}.inib`)}`
1163
- : `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}.inib`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}.inib`)}`
1179
+ const { stdout } = await UtilsServer.exec(Config.isCacheEnabled
1180
+ ? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
1181
+ ? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
1182
+ : `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
1164
1183
  : `${pasteCommand} | ${sortCommand} | ${awkCommand}`, {
1165
1184
  encoding: "utf-8",
1166
1185
  });
@@ -1169,11 +1188,11 @@ export default class Inibase {
1169
1188
  const outputArray = lines.map((line) => {
1170
1189
  const splitedFileColumns = line.split("\t"); // Assuming tab-separated columns
1171
1190
  const outputObject = {};
1172
- // Extract values for each file, including "id.inib"
1191
+ // Extract values for each file, including `id${this.getFileExtension()}`
1173
1192
  filesPathes.forEach((fileName, index) => {
1174
- const Field = Utils.getField(parse(fileName).name, schema);
1175
- if (Field)
1176
- outputObject[Field.key] = File.decode(splitedFileColumns[index], Field?.type, Field?.children, this.salt);
1193
+ const field = Utils.getField(parse(fileName).name, schema);
1194
+ if (field)
1195
+ outputObject[field.key] = File.decode(splitedFileColumns[index], field?.type, field?.children, this.salt);
1177
1196
  });
1178
1197
  return outputObject;
1179
1198
  });
package/dist/utils.d.ts CHANGED
@@ -172,4 +172,8 @@ export declare function FormatObjectCriteriaValue(value: string, isParentArray?:
172
172
  type ValidKey = number | string;
173
173
  export declare const swapKeyValue: <K extends ValidKey, V extends ValidKey>(object: Record<K, V>) => Record<V, K>;
174
174
  export declare function getField(keyPath: string, schema: Schema): Field | null;
175
+ export declare function setField(keyPath: string, schema: Schema, field: Omit<Field, "key" | "type"> & {
176
+ key?: string;
177
+ type?: FieldType | FieldType[];
178
+ }): Field | null | undefined;
175
179
  export {};
package/dist/utils.js CHANGED
@@ -365,3 +365,19 @@ export function getField(keyPath, schema) {
365
365
  return null;
366
366
  return isArrayOfObjects(RETURN) ? RETURN[0] : RETURN;
367
367
  }
368
+ export function setField(keyPath, schema, field) {
369
+ const keyPathSplited = keyPath.split(".");
370
+ for (const [index, key] of keyPathSplited.entries()) {
371
+ const foundItem = schema.find((item) => item.key === key);
372
+ if (!foundItem)
373
+ return null;
374
+ if (index === keyPathSplited.length - 1) {
375
+ Object.assign(foundItem, field);
376
+ return foundItem;
377
+ }
378
+ if ((foundItem.type === "array" || foundItem.type === "object") &&
379
+ foundItem.children &&
380
+ isArrayOfObjects(foundItem.children))
381
+ schema = foundItem.children;
382
+ }
383
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.57",
3
+ "version": "1.0.0-rc.59",
4
4
  "author": {
5
5
  "name": "Karim Amahtil",
6
6
  "email": "karim.amahtil@gmail.com"
@@ -47,6 +47,9 @@
47
47
  "pocketbase"
48
48
  ],
49
49
  "license": "MIT",
50
+ "bin": {
51
+ "inibase": "./dist/cli.js"
52
+ },
50
53
  "type": "module",
51
54
  "types": "./dist",
52
55
  "typesVersions": {
@@ -70,6 +73,7 @@
70
73
  },
71
74
  "devDependencies": {
72
75
  "@types/node": "^20.12.11",
76
+ "dotenv": "^16.4.5",
73
77
  "tinybench": "^2.6.0"
74
78
  },
75
79
  "dependencies": {
@@ -77,9 +81,8 @@
77
81
  },
78
82
  "scripts": {
79
83
  "build": "tsc",
80
- "test": "npx tsx watch --expose-gc --env-file=.env ./index.test",
81
- "benchmark": "npx tsx --env-file=.env ./benchmark/index",
82
- "benchmark:single": "npx tsx --expose-gc --env-file=.env ./benchmark/single",
83
- "benchmark:bulk": "npx tsx --expose-gc --env-file=.env ./benchmark/bulk"
84
+ "benchmark": "tsx ./benchmark/index",
85
+ "benchmark:single": "tsx --expose-gc ./benchmark/single",
86
+ "benchmark:bulk": "tsx --expose-gc ./benchmark/bulk"
84
87
  }
85
88
  }