inibase 1.0.0-rc.23 → 1.0.0-rc.25

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.d.ts CHANGED
@@ -59,7 +59,7 @@ declare global {
59
59
  export default class Inibase {
60
60
  folder: string;
61
61
  database: string;
62
- table: string;
62
+ table: string | null;
63
63
  pageInfo: pageInfo;
64
64
  private cache;
65
65
  private totalItems;
@@ -69,8 +69,9 @@ export default class Inibase {
69
69
  setTableSchema(tableName: string, schema: Schema): Promise<void>;
70
70
  getTableSchema(tableName: string): Promise<Schema | undefined>;
71
71
  getField<Property extends keyof Field | "children">(keyPath: string, schema: Schema | Field, property?: Property): any;
72
- validateData(data: Data | Data[], schema: Schema, skipRequiredField?: boolean): void;
73
- formatData<dataType extends Data | Data[]>(data: dataType, schema: Schema, formatOnlyAvailiableKeys?: boolean): dataType extends Data ? Data : Data[];
72
+ private validateData;
73
+ private formatField;
74
+ private formatData;
74
75
  private getDefaultValue;
75
76
  private joinPathesContents;
76
77
  private getItemsFromSchema;
@@ -78,10 +79,10 @@ export default class Inibase {
78
79
  private applyCriteria;
79
80
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined): Promise<Data | null>;
80
81
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true): Promise<number[] | null>;
81
- post(tableName: string, data: Data | Data[], options: Options | undefined, returnPostedData?: false): Promise<void | null>;
82
+ post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: false): Promise<void | null>;
82
83
  post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
83
84
  post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
84
- put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria | undefined, options?: Options | undefined, returnPostedData?: false): Promise<void | null>;
85
+ put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: false): Promise<void | null>;
85
86
  put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
86
87
  put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
87
88
  delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<string | null>;
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { unlink, rename, readFile, writeFile, mkdir, readdir, } from "node:fs/promises";
2
- import { join, parse } from "node:path";
3
- import { scryptSync } from "node:crypto";
2
+ import { existsSync, appendFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { scryptSync, randomBytes } from "node:crypto";
4
5
  import File from "./file.js";
5
6
  import Utils from "./utils.js";
6
7
  import UtilsServer from "./utils.server.js";
@@ -19,7 +20,13 @@ export default class Inibase {
19
20
  this.cache = new Map();
20
21
  this.totalItems = {};
21
22
  this.pageInfo = { page: 1, per_page: 15 };
22
- this.salt = scryptSync(process.env.INIBASE_SECRET ?? "inibase", (process.env.INIBASE_SECRET ?? "inibase") + "_salt", 32);
23
+ if (!existsSync(".env") || !process.env.INIBASE_SECRET) {
24
+ this.salt = scryptSync(randomBytes(16), randomBytes(16), 32);
25
+ appendFileSync(".env", `INIBASE_SECRET=${this.salt.toString("hex")}\n`);
26
+ }
27
+ else {
28
+ this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
29
+ }
23
30
  }
24
31
  throwError(code, variable, language = "en") {
25
32
  const errorMessages = {
@@ -50,7 +57,7 @@ export default class Inibase {
50
57
  const decodeIdFromSchema = (schema) => schema.map((field) => {
51
58
  if (field.children && Utils.isArrayOfObjects(field.children))
52
59
  field.children = decodeIdFromSchema(field.children);
53
- if (!Utils.isNumber(field.id))
60
+ if (field.id && !Utils.isNumber(field.id))
54
61
  field.id = UtilsServer.decodeID(field.id, this.salt);
55
62
  return field;
56
63
  });
@@ -72,7 +79,7 @@ export default class Inibase {
72
79
  RETURN[UtilsServer.decodeID(field.id, this.salt)] =
73
80
  (prefix ?? "") + field.key + ".inib";
74
81
  return RETURN;
75
- }, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath(await this.getTableSchema(tableName)), schemaToIdsPath(schema));
82
+ }, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath((await this.getTableSchema(tableName)) ?? []), schemaToIdsPath(schema));
76
83
  if (replaceOldPathes)
77
84
  for await (const [oldPath, newPath] of Object.entries(replaceOldPathes))
78
85
  if (await File.isExists(join(TablePath, oldPath)))
@@ -88,7 +95,7 @@ export default class Inibase {
88
95
  this.cache.set(TableSchemaPath, await readFile(TableSchemaPath, "utf8"));
89
96
  if (!this.cache.get(TableSchemaPath))
90
97
  return undefined;
91
- const schema = JSON.parse(this.cache.get(TableSchemaPath)), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
98
+ const schema = JSON.parse(this.cache.get(TableSchemaPath) ?? ""), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
92
99
  return [
93
100
  {
94
101
  id: UtilsServer.encodeID(0, this.salt),
@@ -149,7 +156,7 @@ export default class Inibase {
149
156
  throw this.throwError("FIELD_REQUIRED", key);
150
157
  if (data.hasOwnProperty(key) &&
151
158
  !Utils.validateFieldType(data[key], type, children && !Utils.isArrayOfObjects(children) ? children : undefined))
152
- throw this.throwError("INVALID_TYPE", key);
159
+ throw this.throwError("INVALID_TYPE", key + " " + type + " " + data[key]);
153
160
  if ((type === "array" || type === "object") &&
154
161
  children &&
155
162
  Utils.isArrayOfObjects(children))
@@ -157,85 +164,87 @@ export default class Inibase {
157
164
  }
158
165
  }
159
166
  }
160
- formatData(data, schema, formatOnlyAvailiableKeys) {
161
- this.validateData(data, schema, formatOnlyAvailiableKeys);
162
- const formatField = (value, field) => {
163
- if (Array.isArray(field.type))
164
- field.type = Utils.detectFieldType(value, field.type);
165
- switch (field.type) {
166
- case "array":
167
- if (!Array.isArray(value))
168
- value = [value];
169
- if (typeof field.children === "string") {
170
- if (field.type === "array" && field.children === "table") {
171
- if (Array.isArray(value)) {
172
- if (Utils.isArrayOfObjects(value)) {
173
- if (value.every((item) => item.hasOwnProperty("id") &&
174
- (Utils.isValidID(item.id) || Utils.isNumber(item.id))))
175
- value.map((item) => Utils.isNumber(item.id)
167
+ formatField(value, field, formatOnlyAvailiableKeys) {
168
+ if (Array.isArray(field.type))
169
+ field.type = Utils.detectFieldType(value, field.type) ?? field.type[0];
170
+ switch (field.type) {
171
+ case "array":
172
+ if (!Array.isArray(value))
173
+ value = [value];
174
+ if (typeof field.children === "string") {
175
+ if (field.type === "array" && field.children === "table") {
176
+ if (Array.isArray(value)) {
177
+ if (Utils.isArrayOfObjects(value)) {
178
+ if (value.every((item) => item.hasOwnProperty("id") &&
179
+ (Utils.isValidID(item.id) || Utils.isNumber(item.id))))
180
+ value.map((item) => item.id
181
+ ? Utils.isNumber(item.id)
176
182
  ? Number(item.id)
177
- : UtilsServer.decodeID(item.id, this.salt));
178
- }
179
- else if (value.every(Utils.isValidID) ||
180
- value.every(Utils.isNumber))
181
- return value.map((item) => Utils.isNumber(item)
182
- ? Number(item)
183
- : UtilsServer.decodeID(item, this.salt));
183
+ : UtilsServer.decodeID(item.id, this.salt)
184
+ : null);
184
185
  }
185
- else if (Utils.isValidID(value))
186
- return [UtilsServer.decodeID(value, this.salt)];
187
- else if (Utils.isNumber(value))
188
- return [Number(value)];
186
+ else if (value.every(Utils.isValidID) ||
187
+ value.every(Utils.isNumber))
188
+ return value.map((item) => Utils.isNumber(item)
189
+ ? Number(item)
190
+ : UtilsServer.decodeID(item, this.salt));
189
191
  }
190
- else if (data.hasOwnProperty(field.key))
191
- return value;
192
- }
193
- else if (Utils.isArrayOfObjects(field.children))
194
- return this.formatData(value, field.children, formatOnlyAvailiableKeys);
195
- else if (Array.isArray(field.children))
196
- return Array.isArray(value) ? value : [value];
197
- break;
198
- case "object":
199
- if (Utils.isArrayOfObjects(field.children))
200
- return this.formatData(value, field.children, formatOnlyAvailiableKeys);
201
- break;
202
- case "table":
203
- if (Array.isArray(value))
204
- value = value[0];
205
- if (Utils.isObject(value)) {
206
- if (value.hasOwnProperty("id") &&
207
- (Utils.isValidID(value.id) ||
208
- Utils.isNumber(value.id)))
209
- return Utils.isNumber(value.id)
210
- ? Number(value.id)
211
- : UtilsServer.decodeID(value.id, this.salt);
192
+ else if (Utils.isValidID(value))
193
+ return [UtilsServer.decodeID(value, this.salt)];
194
+ else if (Utils.isNumber(value))
195
+ return [Number(value)];
212
196
  }
213
- else if (Utils.isValidID(value) || Utils.isNumber(value))
214
- return Utils.isNumber(value)
215
- ? Number(value)
216
- : UtilsServer.decodeID(value, this.salt);
217
- break;
218
- case "password":
219
- if (Array.isArray(value))
220
- value = value[0];
221
- return typeof value === "string" && value.length === 161
222
- ? value
223
- : UtilsServer.hashPassword(String(value));
224
- case "number":
225
- if (Array.isArray(value))
226
- value = value[0];
227
- return Utils.isNumber(value) ? Number(value) : null;
228
- case "id":
229
- if (Array.isArray(value))
230
- value = value[0];
197
+ else if (value.hasOwnProperty(field.key))
198
+ return value;
199
+ }
200
+ else if (Utils.isArrayOfObjects(field.children))
201
+ return this.formatData(value, field.children, formatOnlyAvailiableKeys);
202
+ else if (Array.isArray(field.children))
203
+ return Array.isArray(value) ? value : [value];
204
+ break;
205
+ case "object":
206
+ if (Utils.isArrayOfObjects(field.children))
207
+ return this.formatData(value, field.children, formatOnlyAvailiableKeys);
208
+ break;
209
+ case "table":
210
+ if (Array.isArray(value))
211
+ value = value[0];
212
+ if (Utils.isObject(value)) {
213
+ if (value.hasOwnProperty("id") &&
214
+ (Utils.isValidID(value.id) ||
215
+ Utils.isNumber(value.id)))
216
+ return Utils.isNumber(value.id)
217
+ ? Number(value.id)
218
+ : UtilsServer.decodeID(value.id, this.salt);
219
+ }
220
+ else if (Utils.isValidID(value) || Utils.isNumber(value))
231
221
  return Utils.isNumber(value)
232
- ? value
222
+ ? Number(value)
233
223
  : UtilsServer.decodeID(value, this.salt);
234
- default:
235
- return value;
236
- }
237
- return null;
238
- };
224
+ break;
225
+ case "password":
226
+ if (Array.isArray(value))
227
+ value = value[0];
228
+ return typeof value === "string" && value.length === 161
229
+ ? value
230
+ : UtilsServer.hashPassword(String(value));
231
+ case "number":
232
+ if (Array.isArray(value))
233
+ value = value[0];
234
+ return Utils.isNumber(value) ? Number(value) : null;
235
+ case "id":
236
+ if (Array.isArray(value))
237
+ value = value[0];
238
+ return Utils.isNumber(value)
239
+ ? value
240
+ : UtilsServer.decodeID(value, this.salt);
241
+ default:
242
+ return value;
243
+ }
244
+ return null;
245
+ }
246
+ formatData(data, schema, formatOnlyAvailiableKeys) {
247
+ this.validateData(data, schema, formatOnlyAvailiableKeys);
239
248
  if (Utils.isArrayOfObjects(data))
240
249
  return data.map((single_data) => this.formatData(single_data, schema, formatOnlyAvailiableKeys));
241
250
  else if (Utils.isObject(data)) {
@@ -247,7 +256,7 @@ export default class Inibase {
247
256
  RETURN[field.key] = this.getDefaultValue(field);
248
257
  continue;
249
258
  }
250
- RETURN[field.key] = formatField(data[field.key], field);
259
+ RETURN[field.key] = this.formatField(data[field.key], field, formatOnlyAvailiableKeys);
251
260
  }
252
261
  return RETURN;
253
262
  }
@@ -382,22 +391,24 @@ export default class Inibase {
382
391
  .map((column) => column.replace(`${field.key}.`, ""));
383
392
  const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
384
393
  this.totalItems[tableName + "-" + field.key] = total_lines;
385
- for await (const [index, item] of Object.entries(items)) {
386
- if (!RETURN[index])
387
- RETURN[index] = {};
388
- RETURN[index][field.key] = item
389
- ? await this.get(field.key, item, options)
390
- : this.getDefaultValue(field);
391
- }
394
+ if (items)
395
+ for await (const [index, item] of Object.entries(items)) {
396
+ if (!RETURN[index])
397
+ RETURN[index] = {};
398
+ RETURN[index][field.key] = item
399
+ ? await this.get(field.key, item, options)
400
+ : this.getDefaultValue(field);
401
+ }
392
402
  }
393
403
  else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
394
404
  const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
395
405
  this.totalItems[tableName + "-" + field.key] = total_lines;
396
- for (const [index, item] of Object.entries(items)) {
397
- if (!RETURN[index])
398
- RETURN[index] = {};
399
- RETURN[index][field.key] = item ?? this.getDefaultValue(field);
400
- }
406
+ if (items)
407
+ for (const [index, item] of Object.entries(items)) {
408
+ if (!RETURN[index])
409
+ RETURN[index] = {};
410
+ RETURN[index][field.key] = item ?? this.getDefaultValue(field);
411
+ }
401
412
  }
402
413
  }
403
414
  else if (field.type === "object") {
@@ -424,23 +435,30 @@ export default class Inibase {
424
435
  .map((column) => column.replace(`${field.key}.`, ""));
425
436
  const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
426
437
  this.totalItems[tableName + "-" + field.key] = total_lines;
427
- for await (const [index, item] of Object.entries(items)) {
428
- if (!RETURN[index])
429
- RETURN[index] = {};
430
- RETURN[index][field.key] = item
431
- ? await this.get(field.key, item, options)
432
- : this.getDefaultValue(field);
433
- }
438
+ if (items)
439
+ for await (const [index, item] of Object.entries(items)) {
440
+ if (!RETURN[index])
441
+ RETURN[index] = {};
442
+ RETURN[index][field.key] = item
443
+ ? await this.get(field.key, item, options)
444
+ : this.getDefaultValue(field);
445
+ }
434
446
  }
435
447
  }
436
448
  else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
437
449
  const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
438
450
  this.totalItems[tableName + "-" + field.key] = total_lines;
439
- for (const [index, item] of Object.entries(items)) {
440
- if (!RETURN[index])
441
- RETURN[index] = {};
442
- RETURN[index][field.key] = item ?? this.getDefaultValue(field);
443
- }
451
+ if (items)
452
+ for (const [index, item] of Object.entries(items)) {
453
+ if (!RETURN[index])
454
+ RETURN[index] = {};
455
+ RETURN[index][field.key] = item ?? this.getDefaultValue(field);
456
+ }
457
+ else
458
+ RETURN = Object.fromEntries(Object.entries(RETURN).map(([index, data]) => [
459
+ index,
460
+ { ...data, [field.key]: this.getDefaultValue(field) },
461
+ ]));
444
462
  }
445
463
  }
446
464
  return RETURN;
@@ -528,8 +546,8 @@ export default class Inibase {
528
546
  let searchOperator = undefined, searchComparedAtValue = undefined, searchLogicalOperator = undefined;
529
547
  if (Utils.isObject(value)) {
530
548
  if (value?.or &&
531
- Array.isArray(value.or)) {
532
- const searchCriteria = value.or
549
+ Array.isArray(value?.or)) {
550
+ const searchCriteria = (value?.or)
533
551
  .map((single_or) => typeof single_or === "string"
534
552
  ? this.FormatObjectCriteriaValue(single_or)
535
553
  : ["=", single_or])
@@ -539,11 +557,11 @@ export default class Inibase {
539
557
  searchComparedAtValue = searchCriteria.map((single_or) => single_or[1]);
540
558
  searchLogicalOperator = "or";
541
559
  }
542
- delete value.or;
560
+ delete value?.or;
543
561
  }
544
562
  if (value?.and &&
545
- Array.isArray(value.and)) {
546
- const searchCriteria = value.and
563
+ Array.isArray(value?.and)) {
564
+ const searchCriteria = (value?.and)
547
565
  .map((single_and) => typeof single_and === "string"
548
566
  ? this.FormatObjectCriteriaValue(single_and)
549
567
  : ["=", single_and])
@@ -553,7 +571,7 @@ export default class Inibase {
553
571
  searchComparedAtValue = searchCriteria.map((single_and) => single_and[1]);
554
572
  searchLogicalOperator = "and";
555
573
  }
556
- delete value.and;
574
+ delete value?.and;
557
575
  }
558
576
  }
559
577
  else if (Array.isArray(value)) {
@@ -579,9 +597,14 @@ export default class Inibase {
579
597
  searchOperator = "=";
580
598
  searchComparedAtValue = value;
581
599
  }
582
- const [searchResult, total_lines] = await File.search(join(this.folder, this.database, tableName, key + ".inib"), searchOperator, searchComparedAtValue, searchLogicalOperator, field?.type, field?.children, options.per_page, options.page - 1 * options.per_page + 1, true, this.salt);
600
+ const [searchResult, total_lines] = await File.search(join(this.folder, this.database, tableName, key + ".inib"), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.per_page, options.page - 1 * options.per_page + 1, true, this.salt);
583
601
  if (searchResult) {
584
- RETURN = Utils.deepMerge(RETURN, searchResult);
602
+ RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
603
+ id,
604
+ {
605
+ [key]: value,
606
+ },
607
+ ])));
585
608
  this.totalItems[tableName + "-" + key] = total_lines;
586
609
  }
587
610
  if (allTrue && index > 0) {
@@ -599,12 +622,13 @@ export default class Inibase {
599
622
  page: 1,
600
623
  per_page: 15,
601
624
  }, onlyOne, onlyLinesNumbers) {
602
- if (!options.columns)
603
- options.columns = [];
604
- else if (!Array.isArray(options.columns))
605
- options.columns = [options.columns];
606
- if (options.columns.length && !options.columns.includes("id"))
607
- options.columns.push("id");
625
+ if (options.columns) {
626
+ if (!Array.isArray(options.columns))
627
+ options.columns = [options.columns];
628
+ if (options.columns.length &&
629
+ !options.columns.includes("id"))
630
+ options.columns.push("id");
631
+ }
608
632
  if (!options.page)
609
633
  options.page = 1;
610
634
  if (!options.per_page)
@@ -635,7 +659,7 @@ export default class Inibase {
635
659
  return null;
636
660
  })
637
661
  .filter((i) => i);
638
- if (options.columns.length)
662
+ if (options.columns && options.columns.length)
639
663
  schema = filterSchemaByColumns(schema, options.columns);
640
664
  if (!where) {
641
665
  // Display all data
@@ -658,7 +682,7 @@ export default class Inibase {
658
682
  ? Object.keys(lineNumbers).map(Number)
659
683
  : null;
660
684
  RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
661
- if (RETURN.length && !Array.isArray(where))
685
+ if (RETURN && RETURN.length && !Array.isArray(where))
662
686
  RETURN = RETURN[0];
663
687
  }
664
688
  else if (Utils.isObject(where)) {
@@ -667,7 +691,7 @@ export default class Inibase {
667
691
  if (RETURN) {
668
692
  if (onlyLinesNumbers)
669
693
  return Object.keys(RETURN).map(Number);
670
- const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]).map((key) => parse(key).name);
694
+ const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]);
671
695
  RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter((field) => !alreadyExistsColumns.includes(field.key)), Object.keys(RETURN).map(Number), options)));
672
696
  }
673
697
  }
@@ -700,7 +724,7 @@ export default class Inibase {
700
724
  const idFilePath = join(this.folder, this.database, tableName, "id.inib");
701
725
  let [last_line_number, last_id] = (await File.isExists(idFilePath))
702
726
  ? Object.entries((await File.get(idFilePath, -1, "number", undefined, this.salt))[0] ??
703
- {})[0]?.map(Number) ?? [0, 0]
727
+ {})[0].map(Number) ?? [0, 0]
704
728
  : [0, 0];
705
729
  if (Utils.isArrayOfObjects(data))
706
730
  RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
@@ -720,10 +744,17 @@ export default class Inibase {
720
744
  const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), RETURN);
721
745
  last_line_number += 1;
722
746
  for await (const [path, content] of Object.entries(pathesContents))
723
- await File.append(path, content, last_line_number);
747
+ await File.append(path,
748
+ // Array.isArray(content)
749
+ // ? content.reduce((obj, value, index) => {
750
+ // obj[last_line_number + index] = value;
751
+ // return obj;
752
+ // }, {})
753
+ // : { [last_line_number]: content }
754
+ content, last_line_number);
724
755
  if (returnPostedData)
725
756
  return this.get(tableName, Utils.isArrayOfObjects(RETURN)
726
- ? RETURN.map((data) => data.id)
757
+ ? RETURN.map((data) => Number(data.id))
727
758
  : RETURN.id, options, !Utils.isArrayOfObjects(data) // return only one item if data is not array of objects
728
759
  );
729
760
  }
@@ -742,7 +773,9 @@ export default class Inibase {
742
773
  if (Utils.isArrayOfObjects(data)) {
743
774
  if (!data.every((item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)))
744
775
  throw this.throwError("INVALID_ID");
745
- return this.put(tableName, data, data.map((item) => item.id));
776
+ return this.put(tableName, data, data
777
+ .filter((item) => item.id !== undefined)
778
+ .map((item) => item.id));
746
779
  }
747
780
  else if (data.hasOwnProperty("id")) {
748
781
  if (!Utils.isValidID(data.id))
@@ -825,6 +858,8 @@ export default class Inibase {
825
858
  if ((Array.isArray(where) && where.every(Utils.isValidID)) ||
826
859
  Utils.isValidID(where)) {
827
860
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
861
+ if (!lineNumbers)
862
+ return null;
828
863
  return this.delete(tableName, lineNumbers, where);
829
864
  }
830
865
  else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
@@ -833,7 +868,7 @@ export default class Inibase {
833
868
  const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
834
869
  if (files.length) {
835
870
  if (!_id)
836
- _id = Object.values((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0] ?? {}).map((id) => UtilsServer.encodeID(Number(id), this.salt));
871
+ _id = Object.entries((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0] ?? {}).map(([_key, id]) => UtilsServer.encodeID(Number(id), this.salt));
837
872
  if (!_id.length)
838
873
  throw this.throwError("NO_ITEMS", tableName);
839
874
  for await (const file of files)
@@ -853,7 +888,7 @@ export default class Inibase {
853
888
  return null;
854
889
  }
855
890
  async sum(tableName, columns, where) {
856
- let RETURN;
891
+ let RETURN = {};
857
892
  const schema = await this.getTableSchema(tableName);
858
893
  if (!schema)
859
894
  throw this.throwError("NO_SCHEMA", tableName);
@@ -866,7 +901,9 @@ export default class Inibase {
866
901
  if (await File.isExists(columnPath)) {
867
902
  if (where) {
868
903
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
869
- RETURN[column] = await File.sum(columnPath, lineNumbers);
904
+ RETURN[column] = lineNumbers
905
+ ? await File.sum(columnPath, lineNumbers)
906
+ : 0;
870
907
  }
871
908
  else
872
909
  RETURN[column] = await File.sum(columnPath);
@@ -875,7 +912,7 @@ export default class Inibase {
875
912
  return Array.isArray(columns) ? RETURN : Object.values(RETURN)[0];
876
913
  }
877
914
  async max(tableName, columns, where) {
878
- let RETURN;
915
+ let RETURN = {};
879
916
  const schema = await this.getTableSchema(tableName);
880
917
  if (!schema)
881
918
  throw this.throwError("NO_SCHEMA", tableName);
@@ -888,7 +925,9 @@ export default class Inibase {
888
925
  if (await File.isExists(columnPath)) {
889
926
  if (where) {
890
927
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
891
- RETURN[column] = await File.max(columnPath, lineNumbers);
928
+ RETURN[column] = lineNumbers
929
+ ? await File.max(columnPath, lineNumbers)
930
+ : 0;
892
931
  }
893
932
  else
894
933
  RETURN[column] = await File.max(columnPath);
@@ -897,7 +936,7 @@ export default class Inibase {
897
936
  return RETURN;
898
937
  }
899
938
  async min(tableName, columns, where) {
900
- let RETURN;
939
+ let RETURN = {};
901
940
  const schema = await this.getTableSchema(tableName);
902
941
  if (!schema)
903
942
  throw this.throwError("NO_SCHEMA", tableName);
@@ -910,7 +949,9 @@ export default class Inibase {
910
949
  if (await File.isExists(columnPath)) {
911
950
  if (where) {
912
951
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
913
- RETURN[column] = await File.min(columnPath, lineNumbers);
952
+ RETURN[column] = lineNumbers
953
+ ? await File.min(columnPath, lineNumbers)
954
+ : 0;
914
955
  }
915
956
  else
916
957
  RETURN[column] = await File.min(columnPath);
package/dist/utils.d.ts CHANGED
@@ -2,7 +2,7 @@ import { type FieldType } from "./index.js";
2
2
  export declare const isArrayOfObjects: (input: any) => input is Record<any, any>[];
3
3
  export declare const isArrayOfArrays: (input: any) => input is any[][];
4
4
  export declare const isArrayOfNulls: (input: any) => input is null[] | null[][];
5
- export declare const isObject: (obj: any) => boolean;
5
+ export declare const isObject: (obj: any) => obj is Record<any, any>;
6
6
  export declare const deepMerge: (target: any, source: any) => any;
7
7
  export declare const combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
8
8
  export declare const isNumber: (input: any) => input is number;
@@ -21,7 +21,7 @@ export declare const validateFieldType: (value: any, fieldType: FieldType | Fiel
21
21
  export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
22
22
  export default class Utils {
23
23
  static isNumber: (input: any) => input is number;
24
- static isObject: (obj: any) => boolean;
24
+ static isObject: (obj: any) => obj is Record<any, any>;
25
25
  static isEmail: (input: any) => boolean;
26
26
  static isDate: (input: any) => boolean;
27
27
  static isURL: (input: any) => boolean;
@@ -30,14 +30,14 @@ export default class Utils {
30
30
  static deepMerge: (target: any, source: any) => any;
31
31
  static combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
32
32
  static isArrayOfObjects: (input: any) => input is Record<any, any>[];
33
- static findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string>;
34
- static detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType;
33
+ static findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string> | null;
34
+ static detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
35
35
  static isArrayOfArrays: (input: any) => input is any[][];
36
36
  static isBoolean: (input: any) => input is boolean;
37
37
  static isString: (input: any) => input is string;
38
38
  static isHTML: (input: any) => boolean;
39
39
  static isIP: (input: any) => boolean;
40
- static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
40
+ static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | undefined) => boolean;
41
41
  static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
42
42
  static isArrayOfNulls: (input: any) => input is null[] | null[][];
43
43
  }
package/dist/utils.js CHANGED
@@ -54,12 +54,10 @@ export const isEmail = (input) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(input
54
54
  export const isURL = (input) => {
55
55
  if (typeof input !== "string")
56
56
  return false;
57
- if (input[0] === "#" ||
57
+ if ((input[0] === "#" && !input.includes(" ")) ||
58
58
  input.startsWith("tel:") ||
59
59
  input.startsWith("mailto:"))
60
60
  return true;
61
- else if ("canParse" in URL)
62
- return URL.canParse(input);
63
61
  else {
64
62
  var pattern = new RegExp("^(https?:\\/\\/)?" + // protocol
65
63
  "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
@@ -72,13 +70,7 @@ export const isURL = (input) => {
72
70
  };
73
71
  export const isHTML = (input) => /<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)/g.test(input);
74
72
  export const isString = (input) => Object.prototype.toString.call(input) === "[object String]" &&
75
- !isNumber(input) &&
76
- !isBoolean(input) &&
77
- !isEmail(input) &&
78
- !isDate(input) &&
79
- !isURL(input) &&
80
- !isIP(input) &&
81
- !isHTML(input);
73
+ [isNumber, isBoolean, isEmail, isURL, isIP].every((fn) => !fn(input));
82
74
  export const isIP = (input) => /^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(input);
83
75
  export const isBoolean = (input) => typeof input === "boolean" ||
84
76
  input === "true" ||
@@ -86,8 +78,7 @@ export const isBoolean = (input) => typeof input === "boolean" ||
86
78
  input === true ||
87
79
  input === false;
88
80
  export const isPassword = (input) => input.length === 161;
89
- export const isDate = (input) => (isNumber(input) && new Date(input).getTime() > 0) ||
90
- (!isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0);
81
+ export const isDate = (input) => !isNaN(new Date(input).getTime()) || !isNaN(Date.parse(input));
91
82
  export const isValidID = (input) => {
92
83
  return typeof input === "string" && input.length === 32;
93
84
  };