inibase 1.0.0-rc.61 → 1.0.0-rc.63

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
@@ -2,10 +2,10 @@
2
2
  import "dotenv/config";
3
3
  import { createInterface } from "node:readline/promises";
4
4
  import { parseArgs } from "node:util";
5
- import Inibase from "./index.js";
6
5
  import { basename } from "node:path";
7
- import { isJSON, isNumber } from "./utils.js";
8
6
  import Inison from "inison";
7
+ import Inibase from "./index.js";
8
+ import { isJSON, isNumber } from "./utils.js";
9
9
  const { path } = parseArgs({
10
10
  options: {
11
11
  path: { type: "string", short: "p" },
@@ -17,18 +17,18 @@ const db = new Inibase(basename(path));
17
17
  const rl = createInterface({
18
18
  input: process.stdin,
19
19
  output: process.stdout,
20
+ prompt: "\u001b[1;36m> \u001b[0m",
20
21
  });
22
+ console.clear();
21
23
  rl.prompt();
22
24
  rl.on("line", async (input) => {
23
25
  const trimedInput = input.trim();
24
26
  if (trimedInput === "clear") {
25
- console.clear();
27
+ process.stdout.write("\x1Bc");
26
28
  rl.prompt();
27
29
  }
28
- if (trimedInput === "info") {
29
- console.warn("war");
30
- console.error("err");
31
- }
30
+ if (trimedInput === "exit")
31
+ process.exit();
32
32
  const splitedInput = trimedInput.match(/[^\s"']+|"([^"]*)"|'([^']*)'/g);
33
33
  if (["get", "post", "delete", "put"].includes(splitedInput[0].toLocaleLowerCase())) {
34
34
  const table = splitedInput[1];
@@ -45,14 +45,16 @@ rl.on("line", async (input) => {
45
45
  },
46
46
  }).values;
47
47
  if (where) {
48
- if (isNumber(where))
48
+ if (where === "'-1'" || where === '"-1"')
49
+ where = -1;
50
+ else if (isNumber(where))
49
51
  where = Number(where);
50
52
  else if (isJSON(where))
51
53
  where = Inison.unstringify(where);
52
54
  }
53
55
  if (data) {
54
56
  if (isJSON(data))
55
- where = Inison.unstringify(data);
57
+ data = Inison.unstringify(data);
56
58
  else
57
59
  data = undefined;
58
60
  }
@@ -85,4 +87,5 @@ rl.on("line", async (input) => {
85
87
  break;
86
88
  }
87
89
  }
90
+ rl.prompt();
88
91
  });
package/dist/file.js CHANGED
@@ -178,11 +178,9 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
178
178
  };
179
179
  export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, secretKey, readWholeFile = false) {
180
180
  let fileHandle = null;
181
- let rl = null;
182
181
  try {
183
182
  fileHandle = await open(filePath, "r");
184
- rl = createReadLineInternface(filePath, fileHandle);
185
- const lines = {};
183
+ const rl = createReadLineInternface(filePath, fileHandle), lines = {};
186
184
  let linesCount = 0;
187
185
  if (!lineNumbers) {
188
186
  for await (const line of rl) {
@@ -225,7 +223,6 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
225
223
  }
226
224
  finally {
227
225
  // Ensure that file handles are closed, even if an error occurred
228
- rl?.close();
229
226
  await fileHandle?.close();
230
227
  }
231
228
  }
@@ -244,12 +241,11 @@ export const replace = async (filePath, replacements) => {
244
241
  if (await isExists(filePath)) {
245
242
  let fileHandle = null;
246
243
  let fileTempHandle = null;
247
- let rl = null;
248
244
  try {
249
245
  let linesCount = 0;
250
246
  fileHandle = await open(filePath, "r");
251
247
  fileTempHandle = await open(fileTempPath, "w");
252
- rl = createReadLineInternface(filePath, fileHandle);
248
+ const rl = createReadLineInternface(filePath, fileHandle);
253
249
  await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
254
250
  transform(line, encoding, callback) {
255
251
  linesCount++;
@@ -265,7 +261,6 @@ export const replace = async (filePath, replacements) => {
265
261
  }
266
262
  finally {
267
263
  // Ensure that file handles are closed, even if an error occurred
268
- rl?.close();
269
264
  await fileHandle?.close();
270
265
  await fileTempHandle?.close();
271
266
  }
@@ -303,11 +298,10 @@ export const append = async (filePath, data, prepend) => {
303
298
  else {
304
299
  let fileHandle = null;
305
300
  let fileTempHandle = null;
306
- let rl = null;
307
301
  try {
308
302
  fileHandle = await open(filePath, "r");
309
303
  fileTempHandle = await open(fileTempPath, "w");
310
- rl = createReadLineInternface(filePath, fileHandle);
304
+ const rl = createReadLineInternface(filePath, fileHandle);
311
305
  let isAppended = false;
312
306
  await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
313
307
  transform(line, _, callback) {
@@ -321,7 +315,6 @@ export const append = async (filePath, data, prepend) => {
321
315
  }
322
316
  finally {
323
317
  // Ensure that file handles are closed, even if an error occurred
324
- rl?.close();
325
318
  await fileHandle?.close();
326
319
  await fileTempHandle?.close();
327
320
  }
@@ -347,37 +340,10 @@ export const remove = async (filePath, linesToDelete) => {
347
340
  if (linesToDelete.some(Number.isNaN))
348
341
  throw new Error("UNVALID_LINE_NUMBERS");
349
342
  const fileTempPath = filePath.replace(/([^/]+)\/?$/, ".tmp/$1");
350
- if (linesToDelete.length < 1000) {
351
- const command = filePath.endsWith(".gz")
352
- ? `zcat ${filePath} | sed "${linesToDelete.join("d;")}d" | gzip > ${fileTempPath}`
353
- : `sed "${linesToDelete.join("d;")}d" ${filePath} > ${fileTempPath}`;
354
- await exec(command);
355
- }
356
- else {
357
- let linesCount = 0;
358
- let deletedCount = 0;
359
- const fileHandle = await open(filePath, "r");
360
- const fileTempHandle = await open(fileTempPath, "w");
361
- const linesToDeleteArray = new Set(linesToDelete);
362
- const rl = createReadLineInternface(filePath, fileHandle);
363
- await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
364
- transform(line, _, callback) {
365
- linesCount++;
366
- if (linesToDeleteArray.has(linesCount)) {
367
- deletedCount++;
368
- return callback();
369
- }
370
- return callback(null, `${line}\n`);
371
- },
372
- final(callback) {
373
- if (deletedCount === linesCount)
374
- this.push("\n");
375
- return callback();
376
- },
377
- }));
378
- await fileTempHandle.close();
379
- await fileHandle.close();
380
- }
343
+ const command = filePath.endsWith(".gz")
344
+ ? `zcat ${filePath} | sed "${linesToDelete.join("d;")}d" | gzip > ${fileTempPath}`
345
+ : `sed "${linesToDelete.join("d;")}d" ${filePath} > ${fileTempPath}`;
346
+ await exec(command);
381
347
  return [fileTempPath, filePath];
382
348
  };
383
349
  /**
@@ -407,12 +373,11 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
407
373
  let foundItems = 0;
408
374
  const linesNumbers = new Set();
409
375
  let fileHandle = null;
410
- let rl = null;
411
376
  try {
412
377
  // Open the file for reading.
413
378
  fileHandle = await open(filePath, "r");
414
379
  // Create a Readline interface to read the file line by line.
415
- rl = createReadLineInternface(filePath, fileHandle);
380
+ const rl = createReadLineInternface(filePath, fileHandle);
416
381
  // Iterate through each line in the file.
417
382
  for await (const line of rl) {
418
383
  // Increment the line count for each line.
@@ -452,7 +417,6 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
452
417
  }
453
418
  finally {
454
419
  // Close the file handle in the finally block to ensure it is closed even if an error occurs.
455
- rl?.close();
456
420
  await fileHandle?.close();
457
421
  }
458
422
  };
@@ -469,15 +433,13 @@ export const count = async (filePath) => {
469
433
  let linesCount = 0;
470
434
  if (await isExists(filePath)) {
471
435
  let fileHandle = null;
472
- let rl = null;
473
436
  try {
474
437
  fileHandle = await open(filePath, "r");
475
- rl = createReadLineInternface(filePath, fileHandle);
438
+ const rl = createReadLineInternface(filePath, fileHandle);
476
439
  for await (const _ of rl)
477
440
  linesCount++;
478
441
  }
479
442
  finally {
480
- rl?.close();
481
443
  await fileHandle?.close();
482
444
  }
483
445
  }
@@ -493,27 +455,31 @@ export const count = async (filePath) => {
493
455
  * Note: Decodes each line as a number using the 'decode' function. Non-numeric lines contribute 0 to the sum.
494
456
  */
495
457
  export const sum = async (filePath, lineNumbers) => {
496
- let sum = 0;
497
- const fileHandle = await open(filePath, "r");
498
- const rl = createReadLineInternface(filePath, fileHandle);
499
- if (lineNumbers) {
500
- let linesCount = 0;
501
- const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
502
- for await (const line of rl) {
503
- linesCount++;
504
- if (!lineNumbersArray.has(linesCount))
505
- continue;
506
- sum += +(decode(line, "number") ?? 0);
507
- lineNumbersArray.delete(linesCount);
508
- if (!lineNumbersArray.size)
509
- break;
458
+ let sum = 0, fileHandle = null;
459
+ try {
460
+ fileHandle = await open(filePath, "r");
461
+ const rl = createReadLineInternface(filePath, fileHandle);
462
+ if (lineNumbers) {
463
+ let linesCount = 0;
464
+ const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
465
+ for await (const line of rl) {
466
+ linesCount++;
467
+ if (!lineNumbersArray.has(linesCount))
468
+ continue;
469
+ sum += +(decode(line, "number") ?? 0);
470
+ lineNumbersArray.delete(linesCount);
471
+ if (!lineNumbersArray.size)
472
+ break;
473
+ }
510
474
  }
475
+ else
476
+ for await (const line of rl)
477
+ sum += +(decode(line, "number") ?? 0);
478
+ return sum;
479
+ }
480
+ finally {
481
+ await fileHandle?.close();
511
482
  }
512
- else
513
- for await (const line of rl)
514
- sum += +(decode(line, "number") ?? 0);
515
- await fileHandle.close();
516
- return sum;
517
483
  };
518
484
  /**
519
485
  * Asynchronously finds the maximum numerical value from specified lines in a file.
@@ -525,32 +491,36 @@ export const sum = async (filePath, lineNumbers) => {
525
491
  * Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the maximum.
526
492
  */
527
493
  export const max = async (filePath, lineNumbers) => {
528
- let max = 0;
529
- const fileHandle = await open(filePath, "r");
530
- const rl = createReadLineInternface(filePath, fileHandle);
531
- if (lineNumbers) {
532
- let linesCount = 0;
533
- const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
534
- for await (const line of rl) {
535
- linesCount++;
536
- if (!lineNumbersArray.has(linesCount))
537
- continue;
538
- const lineContentNum = +(decode(line, "number") ?? 0);
539
- if (lineContentNum > max)
540
- max = lineContentNum;
541
- lineNumbersArray.delete(linesCount);
542
- if (!lineNumbersArray.size)
543
- break;
494
+ let max = 0, fileHandle = null, rl = null;
495
+ try {
496
+ fileHandle = await open(filePath, "r");
497
+ rl = createReadLineInternface(filePath, fileHandle);
498
+ if (lineNumbers) {
499
+ let linesCount = 0;
500
+ const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
501
+ for await (const line of rl) {
502
+ linesCount++;
503
+ if (!lineNumbersArray.has(linesCount))
504
+ continue;
505
+ const lineContentNum = +(decode(line, "number") ?? 0);
506
+ if (lineContentNum > max)
507
+ max = lineContentNum;
508
+ lineNumbersArray.delete(linesCount);
509
+ if (!lineNumbersArray.size)
510
+ break;
511
+ }
544
512
  }
513
+ else
514
+ for await (const line of rl) {
515
+ const lineContentNum = +(decode(line, "number") ?? 0);
516
+ if (lineContentNum > max)
517
+ max = lineContentNum;
518
+ }
519
+ return max;
520
+ }
521
+ finally {
522
+ await fileHandle?.close();
545
523
  }
546
- else
547
- for await (const line of rl) {
548
- const lineContentNum = +(decode(line, "number") ?? 0);
549
- if (lineContentNum > max)
550
- max = lineContentNum;
551
- }
552
- await fileHandle.close();
553
- return max;
554
524
  };
555
525
  /**
556
526
  * Asynchronously finds the minimum numerical value from specified lines in a file.
@@ -562,30 +532,34 @@ export const max = async (filePath, lineNumbers) => {
562
532
  * Note: Decodes each line as a number using the 'decode' function. Considers only numerical values for determining the minimum.
563
533
  */
564
534
  export const min = async (filePath, lineNumbers) => {
565
- let min = 0;
566
- const fileHandle = await open(filePath, "r");
567
- const rl = createReadLineInternface(filePath, fileHandle);
568
- if (lineNumbers) {
569
- let linesCount = 0;
570
- const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
571
- for await (const line of rl) {
572
- linesCount++;
573
- if (!lineNumbersArray.has(linesCount))
574
- continue;
575
- const lineContentNum = +(decode(line, "number") ?? 0);
576
- if (lineContentNum < min)
577
- min = lineContentNum;
578
- lineNumbersArray.delete(linesCount);
579
- if (!lineNumbersArray.size)
580
- break;
535
+ let min = 0, fileHandle = null;
536
+ try {
537
+ fileHandle = await open(filePath, "r");
538
+ const rl = createReadLineInternface(filePath, fileHandle);
539
+ if (lineNumbers) {
540
+ let linesCount = 0;
541
+ const lineNumbersArray = new Set(Array.isArray(lineNumbers) ? lineNumbers : [lineNumbers]);
542
+ for await (const line of rl) {
543
+ linesCount++;
544
+ if (!lineNumbersArray.has(linesCount))
545
+ continue;
546
+ const lineContentNum = +(decode(line, "number") ?? 0);
547
+ if (lineContentNum < min)
548
+ min = lineContentNum;
549
+ lineNumbersArray.delete(linesCount);
550
+ if (!lineNumbersArray.size)
551
+ break;
552
+ }
581
553
  }
554
+ else
555
+ for await (const line of rl) {
556
+ const lineContentNum = +(decode(line, "number") ?? 0);
557
+ if (lineContentNum < min)
558
+ min = lineContentNum;
559
+ }
560
+ return min;
561
+ }
562
+ finally {
563
+ await fileHandle?.close();
582
564
  }
583
- else
584
- for await (const line of rl) {
585
- const lineContentNum = +(decode(line, "number") ?? 0);
586
- if (lineContentNum < min)
587
- min = lineContentNum;
588
- }
589
- await fileHandle.close();
590
- return min;
591
565
  };
package/dist/index.d.ts CHANGED
@@ -64,8 +64,28 @@ export default class Inibase {
64
64
  private throwError;
65
65
  private getFileExtension;
66
66
  private _schemaToIdsPath;
67
+ /**
68
+ * Create a new table inside database, with predefined schema and config
69
+ *
70
+ * @param {string} tableName
71
+ * @param {Schema} [schema]
72
+ * @param {Config} [config]
73
+ */
67
74
  createTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
75
+ /**
76
+ * Update table schema or config
77
+ *
78
+ * @param {string} tableName
79
+ * @param {Schema} [schema]
80
+ * @param {Config} [config]
81
+ */
68
82
  updateTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
83
+ /**
84
+ * Get table schema and config
85
+ *
86
+ * @param {string} tableName
87
+ * @return {*} {Promise<TableObject>}
88
+ */
69
89
  getTable(tableName: string): Promise<TableObject>;
70
90
  getTableSchema(tableName: string, encodeIDs?: boolean): Promise<Schema | undefined>;
71
91
  private throwErrorIfTableEmpty;
@@ -81,25 +101,105 @@ export default class Inibase {
81
101
  private getItemsFromSchema;
82
102
  private applyCriteria;
83
103
  private _filterSchemaByColumns;
84
- clearCache(tablePath: string): Promise<void>;
104
+ /**
105
+ * Clear table cache
106
+ *
107
+ * @param {string} tableName
108
+ */
109
+ clearCache(tableName: string): Promise<void>;
110
+ /**
111
+ * Retrieve item(s) from a table
112
+ *
113
+ * @param {string} tableName
114
+ * @param {(string | number | (string | number)[] | Criteria | undefined)} [where]
115
+ * @param {(Options | undefined)} [options]
116
+ * @param {true} [onlyOne]
117
+ * @param {undefined} [onlyLinesNumbers]
118
+ * @param {boolean} [_skipIdColumn]
119
+ * @return {*} {(Promise<Data[] | Data | number[] | null>)}
120
+ */
85
121
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, _skipIdColumn?: boolean): Promise<Data | null>;
86
122
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, _skipIdColumn?: boolean): Promise<number[]>;
123
+ /**
124
+ * Create new item(s) in a table
125
+ *
126
+ * @param {string} tableName
127
+ * @param {(Data | Data[])} data Can be array of objects or a single object
128
+ * @param {Options} [options] Pagination options, useful when the returnPostedData param is true
129
+ * @param {boolean} [returnPostedData] By default function returns void, if you want to get the posted data, set this param to true
130
+ * @return {*} {Promise<Data | Data[] | null | void>}
131
+ */
87
132
  post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
88
133
  post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
89
134
  post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
135
+ /**
136
+ * Update item(s) in a table
137
+ *
138
+ * @param {string} tableName
139
+ * @param {(Data | Data[])} data
140
+ * @param {(number | string | (number | string)[] | Criteria)} [where]
141
+ * @param {Options} [options]
142
+ * @param {false} [returnUpdatedData]
143
+ * @return {*} {Promise<Data | Data[] | null | undefined | void>}
144
+ */
90
145
  put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnUpdatedData?: false): Promise<void>;
91
146
  put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data | null>;
92
147
  put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data[] | null>;
148
+ /**
149
+ * Delete item(s) in a table
150
+ *
151
+ * @param {string} tableName
152
+ * @param {(number | string)} [where]
153
+ * @param {(string | string[])} [_id]
154
+ * @return {*} {(Promise<string | number | (string | number)[] | null>)}
155
+ */
93
156
  delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<string | null>;
94
157
  delete(tableName: string, where?: (number | string)[] | Criteria, _id?: string | string[]): Promise<string[] | null>;
95
158
  delete(tableName: string, where?: number, _id?: string | string[]): Promise<number | null>;
96
159
  delete(tableName: string, where?: number[], _id?: string | string[]): Promise<number[] | null>;
160
+ /**
161
+ * Generate sum of column(s) in a table
162
+ *
163
+ * @param {string} tableName
164
+ * @param {string} columns
165
+ * @param {(number | string | (number | string)[] | Criteria)} [where]
166
+ * @return {*} {Promise<number | Record<string, number>>}
167
+ */
97
168
  sum(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
98
169
  sum(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
170
+ /**
171
+ * Generate max of column(s) in a table
172
+ *
173
+ * @param {string} tableName
174
+ * @param {string} columns
175
+ * @param {(number | string | (number | string)[] | Criteria)} [where]
176
+ * @return {*} {Promise<number>}
177
+ */
99
178
  max(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
100
179
  max(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
180
+ /**
181
+ * Generate min of column(s) in a table
182
+ *
183
+ * @param {string} tableName
184
+ * @param {string} columns
185
+ * @param {(number | string | (number | string)[] | Criteria)} [where]
186
+ * @return {*} {Promise<number>}
187
+ */
101
188
  min(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
102
189
  min(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
190
+ /**
191
+ * Sort column(s) of a table
192
+ *
193
+ * @param {string} tableName
194
+ * @param {(string
195
+ * | string[]
196
+ * | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
197
+ * @param {(string | number | (string | number)[] | Criteria)} [where]
198
+ * @param {Options} [options={
199
+ * page: 1,
200
+ * perPage: 15,
201
+ * }]
202
+ */
103
203
  sort(tableName: string, columns: string | string[] | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">, where?: string | number | (string | number)[] | Criteria, options?: Options): Promise<any[]>;
104
204
  }
105
205
  export {};
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import "dotenv/config";
2
- import { unlink, rename, mkdir, readdir, open, writeFile, readFile, } from "node:fs/promises";
2
+ import { unlink, rename, mkdir, readdir, writeFile, readFile, } from "node:fs/promises";
3
3
  import { existsSync, appendFileSync, readFileSync } from "node:fs";
4
4
  import { join, parse } from "node:path";
5
5
  import { scryptSync, randomBytes } from "node:crypto";
@@ -81,54 +81,65 @@ export default class Inibase {
81
81
  RETURN[field.id] = `${(prefix ?? "") + field.key}${this.getFileExtension(tableName)}`;
82
82
  return RETURN;
83
83
  };
84
+ /**
85
+ * Create a new table inside database, with predefined schema and config
86
+ *
87
+ * @param {string} tableName
88
+ * @param {Schema} [schema]
89
+ * @param {Config} [config]
90
+ */
84
91
  async createTable(tableName, schema, config) {
85
92
  const tablePath = join(this.databasePath, tableName);
86
93
  if (await File.isExists(tablePath))
87
94
  this.throwError("TABLE_EXISTS", tableName);
88
- await Promise.all([
89
- mkdir(tablePath, { recursive: true }),
90
- mkdir(join(tablePath, ".tmp")),
91
- mkdir(join(tablePath, ".cache")),
92
- ]);
95
+ await mkdir(join(tablePath, ".tmp"), { recursive: true });
96
+ await mkdir(join(tablePath, ".cache"));
93
97
  if (config) {
94
98
  if (config.compression)
95
- await open(join(tablePath, ".compression.config"), "w");
99
+ await writeFile(join(tablePath, ".compression.config"), "");
96
100
  if (config.cache)
97
- await open(join(tablePath, ".cache.config"), "w");
101
+ await writeFile(join(tablePath, ".cache.config"), "");
98
102
  if (config.prepend)
99
- await open(join(tablePath, ".prepend.config"), "w");
103
+ await writeFile(join(tablePath, ".prepend.config"), "");
100
104
  }
101
105
  if (schema)
102
106
  await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, 0, this.salt, false), null, 2));
103
107
  }
108
+ /**
109
+ * Update table schema or config
110
+ *
111
+ * @param {string} tableName
112
+ * @param {Schema} [schema]
113
+ * @param {Config} [config]
114
+ */
104
115
  async updateTable(tableName, schema, config) {
105
116
  const table = await this.getTable(tableName), tablePath = join(this.databasePath, tableName);
106
117
  if (config) {
107
118
  if (config.compression !== undefined) {
108
119
  if (!config.compression && table.config.compression) {
109
120
  try {
110
- await UtilsServer.exec(`gunzip -r ${tablePath}/*.txt.gz 2>/dev/null`);
121
+ await UtilsServer.exec(`gunzip ${tablePath}/*.${this.fileExtension}.gz 2>/dev/null`);
111
122
  await unlink(join(tablePath, ".compression.config"));
112
123
  }
113
124
  catch { }
114
125
  }
115
126
  else if (config.compression && !table.config.compression) {
116
127
  try {
117
- await UtilsServer.exec(`gzip -r ${tablePath}/*.txt 2>/dev/null`);
118
- await open(join(tablePath, ".compression.config"), "w");
128
+ await UtilsServer.exec(`gzip ${tablePath}/*.${this.fileExtension} 2>/dev/null`);
129
+ await writeFile(join(tablePath, ".compression.config"), "");
119
130
  }
120
131
  catch { }
121
132
  }
122
133
  }
123
134
  if (config.cache !== undefined) {
124
135
  if (config.cache && !table.config.cache)
125
- await open(join(tablePath, ".cache.config"), "w");
136
+ await writeFile(join(tablePath, ".cache.config"), "");
126
137
  else if (!config.cache && table.config.cache)
127
138
  await unlink(join(tablePath, ".cache.config"));
128
139
  }
129
140
  if (config.prepend !== undefined) {
130
141
  if (config.prepend && !table.config.prepend)
131
- await open(join(tablePath, ".prepend.config"), "w");
142
+ await writeFile(join(tablePath, ".prepend.config"), "");
132
143
  else if (!config.prepend && table.config.prepend)
133
144
  await unlink(join(tablePath, ".prepend.config"));
134
145
  }
@@ -157,6 +168,12 @@ export default class Inibase {
157
168
  delete this.tables[tableName];
158
169
  }
159
170
  }
171
+ /**
172
+ * Get table schema and config
173
+ *
174
+ * @param {string} tableName
175
+ * @return {*} {Promise<TableObject>}
176
+ */
160
177
  async getTable(tableName) {
161
178
  const tablePath = join(this.databasePath, tableName);
162
179
  if (!(await File.isExists(tablePath)))
@@ -749,10 +766,13 @@ export default class Inibase {
749
766
  })
750
767
  .filter((i) => i);
751
768
  }
752
- async clearCache(tablePath) {
753
- await Promise.all((await readdir(join(tablePath, ".cache")))
754
- ?.filter((fileName) => fileName !== `pagination${this.fileExtension}`)
755
- .map(async (file) => unlink(join(tablePath, ".cache", file))));
769
+ /**
770
+ * Clear table cache
771
+ *
772
+ * @param {string} tableName
773
+ */
774
+ async clearCache(tableName) {
775
+ await Promise.all((await readdir(join(this.databasePath, tableName, ".cache"))).map((file) => unlink(join(this.databasePath, tableName, ".cache", file))));
756
776
  }
757
777
  async get(tableName, where, options = {
758
778
  page: 1,
@@ -924,7 +944,7 @@ export default class Inibase {
924
944
  renameList = [];
925
945
  totalItems += Array.isArray(RETURN) ? RETURN.length : 1;
926
946
  if (this.tables[tableName].config.cache)
927
- await this.clearCache(tablePath);
947
+ await this.clearCache(tableName);
928
948
  await writeFile(join(tablePath, ".pagination"), `${lastId},${totalItems}`);
929
949
  if (returnPostedData)
930
950
  return this.get(tableName, this.tables[tableName].config.prepend
@@ -954,6 +974,7 @@ export default class Inibase {
954
974
  if (Utils.isArrayOfObjects(data)) {
955
975
  if (!data.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
956
976
  throw this.throwError("INVALID_ID");
977
+ // TODO: Reduce I/O
957
978
  return this.put(tableName, data, data
958
979
  .filter(({ id }) => id !== undefined)
959
980
  .map(({ id }) => id));
@@ -1022,7 +1043,7 @@ export default class Inibase {
1022
1043
  await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
1023
1044
  renameList = [];
1024
1045
  if (this.tables[tableName].config.cache)
1025
- await this.clearCache(tablePath);
1046
+ await this.clearCache(tableName);
1026
1047
  if (returnUpdatedData)
1027
1048
  return this.get(tableName, where, options, !Array.isArray(where));
1028
1049
  }
@@ -1052,7 +1073,7 @@ export default class Inibase {
1052
1073
  ?.filter((fileName) => fileName.endsWith(".inib"))
1053
1074
  .map(async (file) => unlink(join(tablePath, file))));
1054
1075
  if (this.tables[tableName].config.cache)
1055
- await this.clearCache(tablePath);
1076
+ await this.clearCache(tableName);
1056
1077
  }
1057
1078
  finally {
1058
1079
  await File.unlock(join(tablePath, ".tmp"));
@@ -1074,7 +1095,7 @@ export default class Inibase {
1074
1095
  await Promise.all(files.map(async (file) => renameList.push(await File.remove(join(tablePath, file), where))));
1075
1096
  await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
1076
1097
  if (this.tables[tableName].config.cache)
1077
- await this.clearCache(tablePath);
1098
+ await this.clearCache(tableName);
1078
1099
  if (await File.isExists(join(tablePath, ".pagination"))) {
1079
1100
  const [lastId, totalItems] = (await readFile(join(tablePath, ".pagination"), "utf8"))
1080
1101
  .split(",")
@@ -1163,6 +1184,19 @@ export default class Inibase {
1163
1184
  }
1164
1185
  return RETURN;
1165
1186
  }
1187
+ /**
1188
+ * Sort column(s) of a table
1189
+ *
1190
+ * @param {string} tableName
1191
+ * @param {(string
1192
+ * | string[]
1193
+ * | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
1194
+ * @param {(string | number | (string | number)[] | Criteria)} [where]
1195
+ * @param {Options} [options={
1196
+ * page: 1,
1197
+ * perPage: 15,
1198
+ * }]
1199
+ */
1166
1200
  async sort(tableName, columns, where, options = {
1167
1201
  page: 1,
1168
1202
  perPage: 15,
package/dist/utils.d.ts CHANGED
@@ -169,9 +169,34 @@ export declare function FormatObjectCriteriaValue(value: string, isParentArray?:
169
169
  ComparisonOperator,
170
170
  string | number | boolean | null | (string | number | null)[]
171
171
  ];
172
+ /**
173
+ * Get field from schema
174
+ *
175
+ * @export
176
+ * @param {string} keyPath Support dot notation path
177
+ * @param {Schema} schema
178
+ */
172
179
  export declare function getField(keyPath: string, schema: Schema): Field | null;
180
+ /**
181
+ * Override a schema field, key, type or other properties
182
+ *
183
+ * @export
184
+ * @param {string} keyPath Support dot notation path
185
+ * @param {Schema} schema
186
+ * @param {(Omit<Field, "key" | "type"> & {
187
+ * key?: string;
188
+ * type?: FieldType | FieldType[];
189
+ * })} field
190
+ */
173
191
  export declare function setField(keyPath: string, schema: Schema, field: Omit<Field, "key" | "type"> & {
174
192
  key?: string;
175
193
  type?: FieldType | FieldType[];
176
194
  }): Field | null | undefined;
195
+ /**
196
+ * Remove field from schema
197
+ *
198
+ * @export
199
+ * @param {string} keyPath Support dot notation path
200
+ * @param {Schema} schema
201
+ */
177
202
  export declare function unsetField(keyPath: string, schema: Schema): Field | null | undefined;
package/dist/utils.js CHANGED
@@ -346,6 +346,13 @@ export function FormatObjectCriteriaValue(value, isParentArray = false) {
346
346
  return ["=", value];
347
347
  }
348
348
  }
349
+ /**
350
+ * Get field from schema
351
+ *
352
+ * @export
353
+ * @param {string} keyPath Support dot notation path
354
+ * @param {Schema} schema
355
+ */
349
356
  export function getField(keyPath, schema) {
350
357
  let RETURN = null;
351
358
  const keyPathSplited = keyPath.split(".");
@@ -364,6 +371,17 @@ export function getField(keyPath, schema) {
364
371
  return null;
365
372
  return isArrayOfObjects(RETURN) ? RETURN[0] : RETURN;
366
373
  }
374
+ /**
375
+ * Override a schema field, key, type or other properties
376
+ *
377
+ * @export
378
+ * @param {string} keyPath Support dot notation path
379
+ * @param {Schema} schema
380
+ * @param {(Omit<Field, "key" | "type"> & {
381
+ * key?: string;
382
+ * type?: FieldType | FieldType[];
383
+ * })} field
384
+ */
367
385
  export function setField(keyPath, schema, field) {
368
386
  const keyPathSplited = keyPath.split(".");
369
387
  for (const [index, key] of keyPathSplited.entries()) {
@@ -380,6 +398,13 @@ export function setField(keyPath, schema, field) {
380
398
  schema = foundItem.children;
381
399
  }
382
400
  }
401
+ /**
402
+ * Remove field from schema
403
+ *
404
+ * @export
405
+ * @param {string} keyPath Support dot notation path
406
+ * @param {Schema} schema
407
+ */
383
408
  export function unsetField(keyPath, schema) {
384
409
  const keyPathSplited = keyPath.split(".");
385
410
  let parent = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.61",
3
+ "version": "1.0.0-rc.63",
4
4
  "author": {
5
5
  "name": "Karim Amahtil",
6
6
  "email": "karim.amahtil@gmail.com"
@@ -10,7 +10,6 @@
10
10
  "exports": {
11
11
  ".": "./dist/index.js",
12
12
  "./file": "./dist/file.js",
13
- "./config": "./dist/config.js",
14
13
  "./utils": "./dist/utils.js",
15
14
  "./utils.server": "./dist/utils.server.js"
16
15
  },
@@ -63,9 +62,6 @@
63
62
  "utils": [
64
63
  "./dist/utils.d.ts"
65
64
  ],
66
- "config": [
67
- "./dist/config.d.ts"
68
- ],
69
65
  "utils.server": [
70
66
  "./dist/utils.server.d.ts"
71
67
  ]
package/dist/config.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare const isCompressionEnabled: boolean;
2
- export declare const isCacheEnabled: boolean;
3
- export declare const isReverseEnabled: boolean;
package/dist/config.js DELETED
@@ -1,3 +0,0 @@
1
- export const isCompressionEnabled = process.env.INIBASE_COMPRESSION === "true";
2
- export const isCacheEnabled = process.env.INIBASE_CACHE === "true";
3
- export const isReverseEnabled = process.env.INIBASE_REVERSE === "true";