inibase 1.0.0-rc.85 → 1.0.0-rc.87

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/README.md CHANGED
@@ -1,11 +1,11 @@
1
- [![Inibase banner](./.github/assets/banner.jpg)](https://github.com/inicontent/inibase)
2
-
3
1
  # Inibase :pencil:
4
2
 
5
- [![npmjs](https://img.shields.io/npm/dm/inibase.svg?style=flat)](https://www.npmjs.org/package/inibase) [![License](https://img.shields.io/github/license/inicontent/inibase.svg?style=flat&colorA=18181B&colorB=28CF8D)](./LICENSE) [![Activity](https://img.shields.io/github/commit-activity/m/inicontent/inibase)](https://github.com/inicontent/inibase/pulse) [![GitHub stars](https://img.shields.io/github/stars/inicontent/inibase?style=social)](https://github.com/inicontent/inibase)
6
-
7
3
  > A file-based & memory-efficient, serverless, ACID compliant, relational database management system :fire:
8
4
 
5
+ [![Inibase banner](./.github/assets/banner.jpg)](https://github.com/inicontent/inibase)
6
+
7
+ [![npmjs](https://img.shields.io/npm/dm/inibase.svg?style=flat)](https://www.npmjs.org/package/inibase) [![License](https://img.shields.io/github/license/inicontent/inibase.svg?style=flat&colorA=18181B&colorB=28CF8D)](./LICENSE) [![Activity](https://img.shields.io/github/commit-activity/m/inicontent/inibase)](https://github.com/inicontent/inibase/pulse) [![GitHub stars](https://img.shields.io/github/stars/inicontent/inibase?style=social)](https://github.com/inicontent/inibase)
8
+
9
9
  ## Features
10
10
 
11
11
  - **Lightweight** 🪶
@@ -13,7 +13,7 @@
13
13
  - **100% TypeScript** :large_blue_diamond:
14
14
  - **Super-Fast** :zap: (built-in caching system)
15
15
  - **ATOMIC** :lock: File lock for writing
16
- - **Built-in form-validation** included :sunglasses:
16
+ - **Built-in** form validation (+unique values :new: ) :sunglasses:
17
17
  - **Suitable for large data** :page_with_curl: (tested with 4M records)
18
18
  - **Support Compression** :eight_spoked_asterisk: (using built-in nodejs zlib)
19
19
  - **Support Table Joins** :link:
@@ -42,6 +42,7 @@ const users = await db.get("user", undefined, {
42
42
  // Get items from "user" table where "favoriteFoods" does not includes "Pizza" or "Burger"
43
43
  const users = await db.get("user", { favoriteFoods: "![]Pizza,Burger" });
44
44
  ```
45
+
45
46
  > [!NOTE]
46
47
  > Enjoy using Inibase? Consider sponsoring us via [PayPal](https://paypal.me/KarimAmahtil) <br>
47
48
  > Your support helps us maintain and improve our services. <br>
@@ -50,12 +51,12 @@ const users = await db.get("user", { favoriteFoods: "![]Pizza,Burger" });
50
51
  ## Install
51
52
 
52
53
  ```js
53
- <npm|pnpm|yarn> install inibase
54
+ <npm|pnpm|yarn|bun> install inibase
54
55
  ```
55
56
 
56
57
  ## How it works?
57
58
 
58
- `Inibase` organizes data into databases, tables, and columns, each stored in separate files.
59
+ `Inibase` organizes data into databases, tables, and columns, each stored in separate files.
59
60
 
60
61
  - **POST**: New data is appended to column files efficiently.
61
62
  - **GET**: Data retrieval is optimized by reading files line-by-line.
@@ -88,6 +89,7 @@ interface {
88
89
  prepend: boolean;
89
90
  }
90
91
  ```
92
+
91
93
  </blockquote>
92
94
  </details>
93
95
 
@@ -125,6 +127,7 @@ interface ObjectOrArrayOfObjects {
125
127
  children: Schema;
126
128
  }
127
129
  ```
130
+
128
131
  </blockquote>
129
132
  </details>
130
133
 
@@ -210,6 +213,7 @@ const userTableSchema = [
210
213
 
211
214
  await db.createTable("user", userTableSchema, userTableConfig);
212
215
  ```
216
+
213
217
  </blockquote>
214
218
  </details>
215
219
 
@@ -218,18 +222,17 @@ await db.createTable("user", userTableSchema, userTableConfig);
218
222
  <blockquote>
219
223
 
220
224
  <details>
221
- <summary>Add field</summary>
225
+ <summary>Change Name</summary>
222
226
  <blockquote>
223
227
 
224
228
  ```js
225
229
  import Inibase from "inibase";
226
230
  const db = new Inibase("/databaseName");
227
231
 
228
- const userTableSchema = (await db.getTable("user")).schema;
229
- const newUserTableSchema = [...userTableSchema, {key: "phone2", type: "number", required: false}];
230
-
231
- await db.updateTable("user", newUserTableSchema);
232
+ // this will change table name also in joined tables
233
+ await db.updateTable("user", undefined, {name: "userV2"});
232
234
  ```
235
+
233
236
  </blockquote>
234
237
  </details>
235
238
 
@@ -247,6 +250,7 @@ const userTableSchema = (await db.getTable("user")).schema;
247
250
  setField("username", userTableSchema, {key: "fullName"});
248
251
  await db.updateTable("user", newUserTableSchema);
249
252
  ```
253
+
250
254
  </blockquote>
251
255
  </details>
252
256
 
@@ -264,6 +268,7 @@ const userTableSchema = (await db.getTable("user")).schema;
264
268
  unsetField("fullName", userTableSchema);
265
269
  await db.updateTable("user", newUserTableSchema);
266
270
  ```
271
+
267
272
  </blockquote>
268
273
  </details>
269
274
 
@@ -336,12 +341,17 @@ const product = await db.post("product", productTableData);
336
341
  // }
337
342
  // ]
338
343
  ```
344
+
339
345
  </blockquote>
340
346
  </details>
341
347
 
342
348
  </blockquote>
343
349
  </details>
344
350
 
351
+ <details>
352
+ <summary>Methods</summary>
353
+ <blockquote>
354
+
345
355
  <details>
346
356
  <summary>POST</summary>
347
357
  <blockquote>
@@ -467,6 +477,7 @@ const user = await db.get("user", "1d88385d4b1581f8fb059334dec30f4c");
467
477
  // }
468
478
  // }
469
479
  ```
480
+
470
481
  </blockquote>
471
482
  </details>
472
483
 
@@ -510,6 +521,7 @@ const users = await db.get("user", { favoriteFoods: "[]Pizza" });
510
521
  // ...
511
522
  // ]
512
523
  ```
524
+
513
525
  </blockquote>
514
526
  </details>
515
527
 
@@ -526,6 +538,7 @@ const users = await db.get("user", undefined, {
526
538
  columns: ["!username", "!address.street"],
527
539
  });
528
540
  ```
541
+
529
542
  </blockquote>
530
543
  </details>
531
544
 
@@ -549,6 +562,7 @@ await db.put("user", { isActive: false }, "1d88385d4b1581f8fb059334dec30f4c");
549
562
  // set "isActive" to "true" in table "user" by criteria (where "isActive" is equal to "true")
550
563
  await db.put("user", { isActive: false }, { isActive: true });
551
564
  ```
565
+
552
566
  </blockquote>
553
567
  </details>
554
568
 
@@ -569,6 +583,7 @@ await db.put("user", "1d88385d4b1581f8fb059334dec30f4c");
569
583
  // delete "user" by criteria (where "isActive" is equal to "false")
570
584
  await db.put("user", { isActive: false });
571
585
  ```
586
+
572
587
  </blockquote>
573
588
  </details>
574
589
 
@@ -586,6 +601,7 @@ await db.sum("user", "age");
586
601
  // get the sum of column "age" by criteria (where "isActive" is equal to "false") in "user" table
587
602
  await db.sum("user", ["age", ...], { isActive: false });
588
603
  ```
604
+
589
605
  </blockquote>
590
606
  </details>
591
607
 
@@ -603,6 +619,7 @@ await db.max("user", "age");
603
619
  // get the biggest number of column "age" by criteria (where "isActive" is equal to "false") in "user" table
604
620
  await db.max("user", ["age", ...], { isActive: false });
605
621
  ```
622
+
606
623
  </blockquote>
607
624
  </details>
608
625
 
@@ -620,6 +637,7 @@ await db.min("user", "age");
620
637
  // get the smallest number of column "age" by criteria (where "isActive" is equal to "false") in "user" table
621
638
  await db.min("user", ["age", ...], { isActive: false });
622
639
  ```
640
+
623
641
  </blockquote>
624
642
  </details>
625
643
 
@@ -638,6 +656,10 @@ await db.get("user", undefined, { sort: "age" });
638
656
  await db.get("user", undefined, { sort: ["age", "username"] });
639
657
  await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
640
658
  ```
659
+
660
+ </blockquote>
661
+ </details>
662
+
641
663
  </blockquote>
642
664
  </details>
643
665
 
@@ -661,8 +683,8 @@ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
661
683
  | PUT | 33 ms (10.29 mb) | 312 ms (11.06 mb) | 3539 ms (14.87 mb) |
662
684
  | DELETE | 134 ms (13.50 mb) | 1224 ms (16.57 mb) | 7339 ms (11.46 mb) |
663
685
 
664
- > Testing by default with `user` table, with username, email, password fields _so results include password encryption process_ <br>
665
- > To run benchmarks, install *typescript* & *[tsx](https://github.com/privatenumber/tsx)* globally and run `benchmark` `benchmark:bulk` `benchmark:single`
686
+ > Default testing uses a table with username, email, and password fields, ensuring password encryption is included in the process<br>
687
+ > To run benchmarks, install _typescript_ & _[tsx](https://github.com/privatenumber/tsx)_ globally and run `benchmark` by default bulk, for single use `benchmark --single|-s`
666
688
 
667
689
  ## Roadmap
668
690
 
@@ -678,7 +700,7 @@ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
678
700
  - [x] SUM
679
701
  - [x] MAX
680
702
  - [x] MIN
681
- - [ ] Schema supported types:
703
+ - [x] Schema supported types:
682
704
  - [x] String
683
705
  - [x] Number
684
706
  - [x] Boolean
@@ -694,9 +716,10 @@ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
694
716
  - [x] Id
695
717
  - [x] JSON
696
718
  - [ ] TO-DO:
697
- - [x] Improve caching
719
+ - [ ] Ability to search in JSON fields
720
+ - [ ] Re-check used exec functions
721
+ - [ ] Use smart caching (based on N° of queries)
698
722
  - [ ] Commenting the code
699
- - [x] Add property "unique" for schema fields
700
723
  - [ ] Add Backup feature (generate a tar.gz)
701
724
  - [ ] Add Custom field validation property to schema (using RegEx?)
702
725
  - [ ] Features:
@@ -707,4 +730,4 @@ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
707
730
 
708
731
  ## License
709
732
 
710
- [MIT](./LICENSE)
733
+ [MIT](./LICENSE)
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import { createInterface } from "node:readline/promises";
6
6
  import { parseArgs } from "node:util";
7
7
  import Inison from "inison";
8
8
  import { isExists } from "./file.js";
9
- import Inibase from "./index.js";
9
+ import Inibase, {} from "./index.js";
10
10
  import { isJSON, isNumber, setField, unsetField } from "./utils.js";
11
11
  const textGreen = (input) => `\u001b[1;32m${input}\u001b[0m`;
12
12
  const textRed = (input) => `\u001b[1;31m${input}\u001b[0m`;
package/dist/file.js CHANGED
@@ -16,7 +16,7 @@ export const lock = async (folderPath, prefix) => {
16
16
  }
17
17
  catch ({ message }) {
18
18
  if (message.split(":")[0] === "EEXIST")
19
- return await new Promise((resolve, reject) => setTimeout(() => resolve(lock(folderPath, prefix)), 13));
19
+ return await new Promise((resolve) => setTimeout(() => resolve(lock(folderPath, prefix)), 13));
20
20
  }
21
21
  finally {
22
22
  await lockFile?.close();
@@ -250,7 +250,7 @@ export const replace = async (filePath, replacements) => {
250
250
  fileTempHandle = await open(fileTempPath, "w");
251
251
  const rl = createReadLineInternface(filePath, fileHandle);
252
252
  await _pipeline(filePath, rl, fileTempHandle.createWriteStream(), new Transform({
253
- transform(line, encoding, callback) {
253
+ transform(line, _, callback) {
254
254
  linesCount++;
255
255
  const replacement = isObject(replacements)
256
256
  ? Object.hasOwn(replacements, linesCount)
package/dist/index.d.ts CHANGED
@@ -41,15 +41,15 @@ export type Criteria = ({
41
41
  } & {
42
42
  [key: string]: string | number | boolean | undefined | Criteria;
43
43
  }) | null;
44
+ type Entries<T> = {
45
+ [K in keyof T]: [K, T[K]];
46
+ }[keyof T][];
44
47
  declare global {
45
- type Entries<T> = {
46
- [K in keyof T]: [K, T[K]];
47
- }[keyof T][];
48
48
  interface ObjectConstructor {
49
49
  entries<T extends object>(o: T): Entries<T>;
50
50
  }
51
51
  }
52
- export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "NO_ITEMS" | "NO_RESULTS" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS";
52
+ export type ErrorCodes = "FIELD_UNIQUE" | "FIELD_REQUIRED" | "NO_SCHEMA" | "NO_ITEMS" | "INVALID_ID" | "INVALID_TYPE" | "INVALID_PARAMETERS" | "NO_ENV" | "TABLE_EXISTS" | "TABLE_NOT_EXISTS";
53
53
  export type ErrorLang = "en";
54
54
  export default class Inibase {
55
55
  pageInfo: Record<string, pageInfo>;
@@ -66,27 +66,31 @@ export default class Inibase {
66
66
  /**
67
67
  * Create a new table inside database, with predefined schema and config
68
68
  *
69
- * @param {(string|number)} tableName
69
+ * @param {string} tableName
70
70
  * @param {Schema} [schema]
71
71
  * @param {Config} [config]
72
72
  */
73
- createTable(tableName: string | number, schema?: Schema, config?: Config): Promise<void>;
73
+ createTable(tableName: string, schema?: Schema, config?: Config): Promise<void>;
74
+ private replaceStringInFile;
75
+ private replaceStringInSchemas;
74
76
  /**
75
77
  * Update table schema or config
76
78
  *
77
- * @param {(string|number)} tableName
79
+ * @param {string} tableName
78
80
  * @param {Schema} [schema]
79
- * @param {Config} [config]
81
+ * @param {(Config&{name?: string})} [config]
80
82
  */
81
- updateTable(tableName: string | number, schema?: Schema, config?: Config): Promise<void>;
83
+ updateTable(tableName: string, schema?: Schema, config?: Config & {
84
+ name?: string;
85
+ }): Promise<void>;
82
86
  /**
83
87
  * Get table schema and config
84
88
  *
85
- * @param {(string|number)} tableName
89
+ * @param {string} tableName
86
90
  * @return {*} {Promise<TableObject>}
87
91
  */
88
- getTable(tableName: string | number): Promise<TableObject>;
89
- getTableSchema(tableName: string | number, encodeIDs?: boolean): Promise<Schema | undefined>;
92
+ getTable(tableName: string): Promise<TableObject>;
93
+ getTableSchema(tableName: string, encodeIDs?: boolean): Promise<Schema | undefined>;
90
94
  private throwErrorIfTableEmpty;
91
95
  private validateData;
92
96
  private formatField;
@@ -103,85 +107,86 @@ export default class Inibase {
103
107
  /**
104
108
  * Clear table cache
105
109
  *
106
- * @param {(string|number)} tableName
110
+ * @param {string} tableName
107
111
  */
108
- clearCache(tableName: string | number): Promise<void>;
112
+ clearCache(tableName: string): Promise<void>;
109
113
  /**
110
114
  * Retrieve item(s) from a table
111
115
  *
112
- * @param {(string|number)} tableName
116
+ * @param {string} tableName
113
117
  * @param {(string | number | (string | number)[] | Criteria)} [where]
114
118
  * @param {Options} [options]
115
119
  * @param {boolean} [onlyOne]
116
120
  * @param {boolean} [onlyLinesNumbers]
117
121
  * @return {*} {(Promise<Data | number | (Data | number)[] | null>)}
118
122
  */
119
- get(tableName: string | number, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers?: false): Promise<Data | null>;
120
- get(tableName: string | number, where: string | number, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data | null>;
121
- get(tableName: string | number, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data[] | null>;
122
- get(tableName: string | number, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: false | undefined, onlyLinesNumbers: true): Promise<number[] | null>;
123
- get(tableName: string | number, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers: true): Promise<number | null>;
123
+ get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers?: false): Promise<Data | null>;
124
+ get(tableName: string, where: string | number, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data | null>;
125
+ get(tableName: string, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data[] | null>;
126
+ get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: false | undefined, onlyLinesNumbers: true): Promise<number[] | null>;
127
+ get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers: true): Promise<number | null>;
124
128
  /**
125
129
  * Create new item(s) in a table
126
130
  *
127
- * @param {(string|number)} tableName
131
+ * @param {string} tableName
128
132
  * @param {(Data | Data[])} data Can be array of objects or a single object
129
133
  * @param {Options} [options] Pagination options, useful when the returnPostedData param is true
130
134
  * @param {boolean} [returnPostedData] By default function returns void, if you want to get the posted data, set this param to true
131
135
  * @return {*} {Promise<Data | Data[] | null | void>}
132
136
  */
133
- post(tableName: string | number, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
134
- post(tableName: string | number, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
135
- post(tableName: string | number, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
137
+ post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
138
+ post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
139
+ post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
136
140
  /**
137
141
  * Update item(s) in a table
138
142
  *
139
- * @param {(string|number)} tableName
143
+ * @param {string} tableName
140
144
  * @param {(Data | Data[])} data
141
145
  * @param {(number | string | (number | string)[] | Criteria)} [where]
142
146
  * @param {Options} [options]
143
147
  * @param {false} [returnUpdatedData]
144
148
  * @return {*} {Promise<Data | Data[] | null | undefined | void>}
145
149
  */
146
- put(tableName: string | number, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnUpdatedData?: false): Promise<void>;
147
- put(tableName: string | number, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data | null>;
148
- put(tableName: string | number, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data[] | null>;
150
+ put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnUpdatedData?: false): Promise<void>;
151
+ put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data | null>;
152
+ put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data[] | null>;
149
153
  /**
150
154
  * Delete item(s) in a table
151
155
  *
152
- * @param {(string|number)} tableName
156
+ * @param {string} tableName
153
157
  * @param {(number | string | (number | string)[] | Criteria)} [where]
154
158
  * @return {boolean | null} {(Promise<boolean | null>)}
155
159
  */
156
- delete(tableName: string | number, where?: number | string | (number | string)[] | Criteria, _id?: string | string[]): Promise<boolean | null>;
160
+ delete(tableName: string, where?: number | string | (number | string)[] | Criteria, _id?: string | string[]): Promise<boolean | null>;
157
161
  /**
158
162
  * Generate sum of column(s) in a table
159
163
  *
160
- * @param {(string|number)} tableName
164
+ * @param {string} tableName
161
165
  * @param {string} columns
162
166
  * @param {(number | string | (number | string)[] | Criteria)} [where]
163
167
  * @return {*} {Promise<number | Record<string, number>>}
164
168
  */
165
- sum(tableName: string | number, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
166
- sum(tableName: string | number, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
169
+ sum(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
170
+ sum(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
167
171
  /**
168
172
  * Generate max of column(s) in a table
169
173
  *
170
- * @param {(string|number)} tableName
174
+ * @param {string} tableName
171
175
  * @param {string} columns
172
176
  * @param {(number | string | (number | string)[] | Criteria)} [where]
173
177
  * @return {*} {Promise<number>}
174
178
  */
175
- max(tableName: string | number, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
176
- max(tableName: string | number, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
179
+ max(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
180
+ max(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
177
181
  /**
178
182
  * Generate min of column(s) in a table
179
183
  *
180
- * @param {(string|number)} tableName
184
+ * @param {string} tableName
181
185
  * @param {string} columns
182
186
  * @param {(number | string | (number | string)[] | Criteria)} [where]
183
187
  * @return {*} {Promise<number>}
184
188
  */
185
- min(tableName: string | number, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
186
- min(tableName: string | number, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
189
+ min(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
190
+ min(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
187
191
  }
192
+ export {};
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import "dotenv/config";
2
2
  import { randomBytes, scryptSync } from "node:crypto";
3
3
  import { appendFileSync, existsSync, readFileSync } from "node:fs";
4
- import { mkdir, readFile, readdir, rename, unlink, writeFile, } from "node:fs/promises";
4
+ import { mkdir, readFile, readdir, rename, stat, unlink, writeFile, } from "node:fs/promises";
5
5
  import { join, parse } from "node:path";
6
6
  import { inspect } from "node:util";
7
7
  import Inison from "inison";
@@ -41,7 +41,6 @@ export default class Inibase {
41
41
  TABLE_NOT_EXISTS: "Table {variable} doesn't exist",
42
42
  NO_SCHEMA: "Table {variable} does't have a schema",
43
43
  NO_ITEMS: "Table {variable} is empty",
44
- NO_RESULTS: "No results found for table {variable}",
45
44
  INVALID_ID: "The given ID(s) is/are not valid(s)",
46
45
  INVALID_TYPE: "Expect {variable} to be {variable}, got {variable} instead",
47
46
  INVALID_PARAMETERS: "The given parameters are not valid",
@@ -84,14 +83,14 @@ export default class Inibase {
84
83
  /**
85
84
  * Create a new table inside database, with predefined schema and config
86
85
  *
87
- * @param {(string|number)} tableName
86
+ * @param {string} tableName
88
87
  * @param {Schema} [schema]
89
88
  * @param {Config} [config]
90
89
  */
91
90
  async createTable(tableName, schema, config) {
92
- const tablePath = join(this.databasePath, tableName.toString());
91
+ const tablePath = join(this.databasePath, tableName);
93
92
  if (await File.isExists(tablePath))
94
- throw this.throwError("TABLE_EXISTS", tableName.toString());
93
+ throw this.throwError("TABLE_EXISTS", tableName);
95
94
  await mkdir(join(tablePath, ".tmp"), { recursive: true });
96
95
  await mkdir(join(tablePath, ".cache"));
97
96
  // if config not set => load default global env config
@@ -112,20 +111,63 @@ export default class Inibase {
112
111
  if (schema)
113
112
  await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, 0, this.salt), null, 2));
114
113
  }
114
+ // Function to replace the string in one schema.json file
115
+ async replaceStringInFile(filePath, targetString, replaceString) {
116
+ const data = await readFile(filePath, "utf8");
117
+ if (data.includes(targetString)) {
118
+ const updatedContent = data.replaceAll(targetString, replaceString);
119
+ await writeFile(filePath, updatedContent, "utf8");
120
+ }
121
+ }
122
+ // Function to process schema files one by one (sequentially)
123
+ async replaceStringInSchemas(directoryPath, targetString, replaceString) {
124
+ const files = await readdir(directoryPath);
125
+ for (const file of files) {
126
+ const fullPath = join(directoryPath, file);
127
+ const fileStat = await stat(fullPath);
128
+ if (fileStat.isDirectory()) {
129
+ await this.replaceStringInSchemas(fullPath, targetString, replaceString);
130
+ }
131
+ else if (file === "schema.json") {
132
+ await this.replaceStringInFile(fullPath, targetString, replaceString);
133
+ }
134
+ }
135
+ }
115
136
  /**
116
137
  * Update table schema or config
117
138
  *
118
- * @param {(string|number)} tableName
139
+ * @param {string} tableName
119
140
  * @param {Schema} [schema]
120
- * @param {Config} [config]
141
+ * @param {(Config&{name?: string})} [config]
121
142
  */
122
143
  async updateTable(tableName, schema, config) {
123
- const table = await this.getTable(tableName), tablePath = join(this.databasePath, tableName.toString());
144
+ const table = await this.getTable(tableName), tablePath = join(this.databasePath, tableName);
145
+ if (schema) {
146
+ // remove id from schema
147
+ schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
148
+ if (await File.isExists(join(tablePath, "schema.json"))) {
149
+ // update columns files names based on field id
150
+ schema = UtilsServer.addIdToSchema(schema, table.schema?.length
151
+ ? UtilsServer.findLastIdNumber(table.schema, this.salt)
152
+ : 0, this.salt);
153
+ if (table.schema?.length) {
154
+ const replaceOldPathes = Utils.findChangedProperties(this._schemaToIdsPath(tableName, table.schema), this._schemaToIdsPath(tableName, schema));
155
+ if (replaceOldPathes)
156
+ await Promise.all(Object.entries(replaceOldPathes).map(async ([oldPath, newPath]) => {
157
+ if (await File.isExists(join(tablePath, oldPath)))
158
+ await rename(join(tablePath, oldPath), join(tablePath, newPath));
159
+ }));
160
+ }
161
+ }
162
+ else
163
+ schema = UtilsServer.addIdToSchema(schema, 0, this.salt);
164
+ await writeFile(join(tablePath, "schema.json"), JSON.stringify(schema, null, 2));
165
+ }
124
166
  if (config) {
125
167
  if (config.compression !== undefined &&
126
168
  config.compression !== table.config.compression) {
127
169
  await UtilsServer.execFile("find", [
128
- tableName.toString(),
170
+ tableName,
129
171
  "-type",
130
172
  "f",
131
173
  "-name",
@@ -150,7 +192,7 @@ export default class Inibase {
150
192
  if (config.prepend !== undefined &&
151
193
  config.prepend !== table.config.prepend) {
152
194
  await UtilsServer.execFile("find", [
153
- tableName.toString(),
195
+ tableName,
154
196
  "-type",
155
197
  "f",
156
198
  "-name",
@@ -170,40 +212,23 @@ export default class Inibase {
170
212
  else
171
213
  await unlink(join(tablePath, ".prepend.config"));
172
214
  }
173
- }
174
- if (schema) {
175
- // remove id from schema
176
- schema = schema.filter(({ key }) => !["id", "createdAt", "updatedAt"].includes(key));
177
- if (await File.isExists(join(tablePath, "schema.json"))) {
178
- // update columns files names based on field id
179
- schema = UtilsServer.addIdToSchema(schema, table.schema?.length
180
- ? UtilsServer.findLastIdNumber(table.schema, this.salt)
181
- : 0, this.salt);
182
- if (table.schema?.length) {
183
- const replaceOldPathes = Utils.findChangedProperties(this._schemaToIdsPath(tableName, table.schema), this._schemaToIdsPath(tableName, schema));
184
- if (replaceOldPathes)
185
- await Promise.all(Object.entries(replaceOldPathes).map(async ([oldPath, newPath]) => {
186
- if (await File.isExists(join(tablePath, oldPath)))
187
- await rename(join(tablePath, oldPath), join(tablePath, newPath));
188
- }));
189
- }
215
+ if (config.name) {
216
+ await this.replaceStringInSchemas(this.databasePath, `"table": "${tableName}"`, `"table": "${config.name}"`);
217
+ await rename(tablePath, join(this.databasePath, config.name));
190
218
  }
191
- else
192
- schema = UtilsServer.addIdToSchema(schema, 0, this.salt);
193
- await writeFile(join(tablePath, "schema.json"), JSON.stringify(schema, null, 2));
194
219
  }
195
220
  delete this.tables[tableName];
196
221
  }
197
222
  /**
198
223
  * Get table schema and config
199
224
  *
200
- * @param {(string|number)} tableName
225
+ * @param {string} tableName
201
226
  * @return {*} {Promise<TableObject>}
202
227
  */
203
228
  async getTable(tableName) {
204
- const tablePath = join(this.databasePath, tableName.toString());
229
+ const tablePath = join(this.databasePath, tableName);
205
230
  if (!(await File.isExists(tablePath)))
206
- throw this.throwError("TABLE_NOT_EXISTS", tableName.toString());
231
+ throw this.throwError("TABLE_NOT_EXISTS", tableName);
207
232
  if (!this.tables[tableName])
208
233
  this.tables[tableName] = {
209
234
  schema: await this.getTableSchema(tableName),
@@ -216,7 +241,7 @@ export default class Inibase {
216
241
  return this.tables[tableName];
217
242
  }
218
243
  async getTableSchema(tableName, encodeIDs = true) {
219
- const tableSchemaPath = join(this.databasePath, tableName.toString(), "schema.json");
244
+ const tableSchemaPath = join(this.databasePath, tableName, "schema.json");
220
245
  if (!(await File.isExists(tableSchemaPath)))
221
246
  return undefined;
222
247
  const schemaFile = await readFile(tableSchemaPath, "utf8");
@@ -252,9 +277,9 @@ export default class Inibase {
252
277
  async throwErrorIfTableEmpty(tableName) {
253
278
  const table = await this.getTable(tableName);
254
279
  if (!table.schema)
255
- throw this.throwError("NO_SCHEMA", tableName.toString());
256
- if (!(await File.isExists(join(this.databasePath, tableName.toString(), `id${this.getFileExtension(tableName)}`))))
257
- throw this.throwError("NO_ITEMS", tableName.toString());
280
+ throw this.throwError("NO_SCHEMA", tableName);
281
+ if (!(await File.isExists(join(this.databasePath, tableName, `id${this.getFileExtension(tableName)}`))))
282
+ throw this.throwError("NO_ITEMS", tableName);
258
283
  return table;
259
284
  }
260
285
  validateData(data, schema, skipRequiredField = false) {
@@ -364,7 +389,7 @@ export default class Inibase {
364
389
  return null;
365
390
  }
366
391
  async checkUnique(tableName, schema) {
367
- const tablePath = join(this.databasePath, tableName.toString());
392
+ const tablePath = join(this.databasePath, tableName);
368
393
  for await (const [key, values] of Object.entries(this.checkIFunique)) {
369
394
  const field = Utils.getField(key, schema);
370
395
  if (!field)
@@ -456,7 +481,7 @@ export default class Inibase {
456
481
  return RETURN;
457
482
  };
458
483
  joinPathesContents(tableName, data) {
459
- const tablePath = join(this.databasePath, tableName.toString()), combinedData = this._CombineData(data);
484
+ const tablePath = join(this.databasePath, tableName), combinedData = this._CombineData(data);
460
485
  const newCombinedData = {};
461
486
  for (const [key, value] of Object.entries(combinedData))
462
487
  newCombinedData[join(tablePath, `${key}${this.getFileExtension(tableName)}`)] = value;
@@ -504,7 +529,7 @@ export default class Inibase {
504
529
  }
505
530
  }
506
531
  async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
507
- const tablePath = join(this.databasePath, tableName.toString());
532
+ const tablePath = join(this.databasePath, tableName);
508
533
  const RETURN = {};
509
534
  for await (const field of schema) {
510
535
  if ((field.type === "array" ||
@@ -655,7 +680,7 @@ export default class Inibase {
655
680
  return RETURN;
656
681
  }
657
682
  async applyCriteria(tableName, schema, options, criteria, allTrue) {
658
- const tablePath = join(this.databasePath, tableName.toString());
683
+ const tablePath = join(this.databasePath, tableName);
659
684
  let RETURN = {}, RETURN_LineNumbers = null;
660
685
  if (!criteria)
661
686
  return [null, null];
@@ -785,10 +810,10 @@ export default class Inibase {
785
810
  /**
786
811
  * Clear table cache
787
812
  *
788
- * @param {(string|number)} tableName
813
+ * @param {string} tableName
789
814
  */
790
815
  async clearCache(tableName) {
791
- const cacheFolderPath = join(this.databasePath, tableName.toString(), ".cache");
816
+ const cacheFolderPath = join(this.databasePath, tableName, ".cache");
792
817
  await Promise.all((await readdir(cacheFolderPath))
793
818
  .filter((file) => file !== ".pagination")
794
819
  .map((file) => unlink(join(cacheFolderPath, file))));
@@ -797,7 +822,7 @@ export default class Inibase {
797
822
  page: 1,
798
823
  perPage: 15,
799
824
  }, onlyOne, onlyLinesNumbers) {
800
- const tablePath = join(this.databasePath, tableName.toString());
825
+ const tablePath = join(this.databasePath, tableName);
801
826
  // Ensure options.columns is an array
802
827
  if (options.columns) {
803
828
  options.columns = Array.isArray(options.columns)
@@ -812,7 +837,7 @@ export default class Inibase {
812
837
  let RETURN;
813
838
  let schema = (await this.getTable(tableName)).schema;
814
839
  if (!schema)
815
- throw this.throwError("NO_SCHEMA", tableName.toString());
840
+ throw this.throwError("NO_SCHEMA", tableName);
816
841
  if (!(await File.isExists(join(tablePath, `id${this.getFileExtension(tableName)}`))))
817
842
  return null;
818
843
  if (options.columns?.length)
@@ -841,7 +866,7 @@ export default class Inibase {
841
866
  if (where) {
842
867
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
843
868
  if (!lineNumbers?.length)
844
- throw this.throwError("NO_RESULTS", tableName.toString());
869
+ return null;
845
870
  const itemsIDs = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
846
871
  awkCommand = `awk '${itemsIDs.map((id) => `$1 == ${id}`).join(" || ")}'`;
847
872
  }
@@ -952,7 +977,7 @@ export default class Inibase {
952
977
  Ids = [Ids];
953
978
  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);
954
979
  if (!lineNumbers)
955
- throw this.throwError("NO_RESULTS", tableName.toString());
980
+ return null;
956
981
  if (!this.totalItems[`${tableName}-*`])
957
982
  this.totalItems[`${tableName}-*`] = countItems;
958
983
  if (onlyLinesNumbers)
@@ -1024,9 +1049,9 @@ export default class Inibase {
1024
1049
  page: 1,
1025
1050
  perPage: 15,
1026
1051
  };
1027
- const tablePath = join(this.databasePath, tableName.toString()), schema = (await this.getTable(tableName)).schema;
1052
+ const tablePath = join(this.databasePath, tableName), schema = (await this.getTable(tableName)).schema;
1028
1053
  if (!schema)
1029
- throw this.throwError("NO_SCHEMA", tableName.toString());
1054
+ throw this.throwError("NO_SCHEMA", tableName);
1030
1055
  if (!returnPostedData)
1031
1056
  returnPostedData = false;
1032
1057
  let RETURN;
@@ -1098,7 +1123,7 @@ export default class Inibase {
1098
1123
  perPage: 15,
1099
1124
  }, returnUpdatedData) {
1100
1125
  let renameList = [];
1101
- const tablePath = join(this.databasePath, tableName.toString()), schema = (await this.throwErrorIfTableEmpty(tableName)).schema;
1126
+ const tablePath = join(this.databasePath, tableName), schema = (await this.throwErrorIfTableEmpty(tableName)).schema;
1102
1127
  this.validateData(data, schema, true);
1103
1128
  await this.checkUnique(tableName, schema);
1104
1129
  data = this.formatData(data, schema, true);
@@ -1197,13 +1222,13 @@ export default class Inibase {
1197
1222
  /**
1198
1223
  * Delete item(s) in a table
1199
1224
  *
1200
- * @param {(string|number)} tableName
1225
+ * @param {string} tableName
1201
1226
  * @param {(number | string | (number | string)[] | Criteria)} [where]
1202
1227
  * @return {boolean | null} {(Promise<boolean | null>)}
1203
1228
  */
1204
1229
  async delete(tableName, where, _id) {
1205
1230
  const renameList = [];
1206
- const tablePath = join(this.databasePath, tableName.toString());
1231
+ const tablePath = join(this.databasePath, tableName);
1207
1232
  await this.throwErrorIfTableEmpty(tableName);
1208
1233
  if (!where) {
1209
1234
  try {
@@ -1260,7 +1285,7 @@ export default class Inibase {
1260
1285
  }
1261
1286
  async sum(tableName, columns, where) {
1262
1287
  const RETURN = {};
1263
- const tablePath = join(this.databasePath, tableName.toString());
1288
+ const tablePath = join(this.databasePath, tableName);
1264
1289
  await this.throwErrorIfTableEmpty(tableName);
1265
1290
  if (!Array.isArray(columns))
1266
1291
  columns = [columns];
@@ -1281,7 +1306,7 @@ export default class Inibase {
1281
1306
  }
1282
1307
  async max(tableName, columns, where) {
1283
1308
  const RETURN = {};
1284
- const tablePath = join(this.databasePath, tableName.toString());
1309
+ const tablePath = join(this.databasePath, tableName);
1285
1310
  await this.throwErrorIfTableEmpty(tableName);
1286
1311
  if (!Array.isArray(columns))
1287
1312
  columns = [columns];
@@ -1302,7 +1327,7 @@ export default class Inibase {
1302
1327
  }
1303
1328
  async min(tableName, columns, where) {
1304
1329
  const RETURN = {};
1305
- const tablePath = join(this.databasePath, tableName.toString());
1330
+ const tablePath = join(this.databasePath, tableName);
1306
1331
  await this.throwErrorIfTableEmpty(tableName);
1307
1332
  if (!Array.isArray(columns))
1308
1333
  columns = [columns];
package/dist/utils.d.ts CHANGED
@@ -179,7 +179,7 @@ export declare function FormatObjectCriteriaValue(value: string): [
179
179
  * @param {string} keyPath Support dot notation path
180
180
  * @param {Schema} schema
181
181
  */
182
- export declare function getField(keyPath: string, schema: Schema): Field | null;
182
+ export declare function getField(keyPath: string, schema: Schema): Field;
183
183
  /**
184
184
  * Override a schema field, key, type or other properties
185
185
  *
@@ -194,7 +194,7 @@ export declare function getField(keyPath: string, schema: Schema): Field | null;
194
194
  export declare function setField(keyPath: string, schema: Schema, field: Omit<Field, "key" | "type"> & {
195
195
  key?: string;
196
196
  type?: FieldType | FieldType[];
197
- }): Field | null | undefined;
197
+ }): Field;
198
198
  /**
199
199
  * Remove field from schema
200
200
  *
@@ -202,4 +202,4 @@ export declare function setField(keyPath: string, schema: Schema, field: Omit<Fi
202
202
  * @param {string} keyPath Support dot notation path
203
203
  * @param {Schema} schema
204
204
  */
205
- export declare function unsetField(keyPath: string, schema: Schema): Field | null | undefined;
205
+ export declare function unsetField(keyPath: string, schema: Schema): Field;
@@ -55,7 +55,7 @@ export declare const hashString: (str: string) => string;
55
55
  *
56
56
  * Note: Handles various data types and comparison logic, including special handling for passwords and regex patterns.
57
57
  */
58
- export declare const compare: (operator: ComparisonOperator, originalValue: string | number | boolean | null | (string | number | boolean | null)[], comparedValue: string | number | boolean | null | (string | number | boolean | null)[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => Promise<boolean>;
58
+ export declare const compare: (operator: ComparisonOperator, originalValue: string | number | boolean | null | (string | number | boolean | null)[], comparedValue: string | number | boolean | null | (string | number | boolean | null)[], fieldType?: FieldType | FieldType[]) => boolean;
59
59
  /**
60
60
  * Helper function to check equality based on the field type.
61
61
  *
@@ -141,15 +141,13 @@ export const hashString = (str) => createHash("sha256").update(str).digest("hex"
141
141
  *
142
142
  * Note: Handles various data types and comparison logic, including special handling for passwords and regex patterns.
143
143
  */
144
- export const compare = async (operator, originalValue, comparedValue, fieldType, fieldChildrenType) => {
144
+ export const compare = (operator, originalValue, comparedValue, fieldType) => {
145
145
  // Determine the field type if it's an array of potential types.
146
- if (Array.isArray(fieldType)) {
146
+ if (Array.isArray(fieldType))
147
147
  fieldType = detectFieldType(String(originalValue), fieldType);
148
- }
149
148
  // Handle comparisons involving arrays.
150
- if (Array.isArray(comparedValue) && !["[]", "![]"].includes(operator)) {
149
+ if (Array.isArray(comparedValue) && !["[]", "![]"].includes(operator))
151
150
  return comparedValue.some((value) => compare(operator, originalValue, value, fieldType));
152
- }
153
151
  // Switch statement for different comparison operators.
154
152
  switch (operator) {
155
153
  // Equal (Case Insensitive for strings, specific handling for passwords and booleans).
@@ -223,16 +221,13 @@ export const isEqual = (originalValue, comparedValue, fieldType) => {
223
221
  * @returns boolean - Result of the array equality check.
224
222
  */
225
223
  export const isArrayEqual = (originalValue, comparedValue) => {
226
- if (Array.isArray(originalValue) && Array.isArray(comparedValue)) {
224
+ if (Array.isArray(originalValue) && Array.isArray(comparedValue))
227
225
  return originalValue.some((v) => comparedValue.includes(v));
228
- }
229
- if (Array.isArray(originalValue)) {
226
+ if (Array.isArray(originalValue))
230
227
  return originalValue.includes(comparedValue);
231
- }
232
- if (Array.isArray(comparedValue)) {
228
+ if (Array.isArray(comparedValue))
233
229
  return comparedValue.includes(originalValue);
234
- }
235
- return originalValue === comparedValue;
230
+ return originalValue == comparedValue;
236
231
  };
237
232
  /**
238
233
  * Helper function to check wildcard pattern matching using regex.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.85",
3
+ "version": "1.0.0-rc.87",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Karim Amahtil",