inibase 1.0.0-rc.22 → 1.0.0-rc.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,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
  }
@@ -685,10 +709,14 @@ export default class Inibase {
685
709
  };
686
710
  return onlyOne && Array.isArray(RETURN) ? RETURN[0] : RETURN;
687
711
  }
688
- async post(tableName, data, options = {
689
- page: 1,
690
- per_page: 15,
691
- }, returnPostedData = true) {
712
+ async post(tableName, data, options, returnPostedData) {
713
+ if (!options)
714
+ options = {
715
+ page: 1,
716
+ per_page: 15,
717
+ };
718
+ if (!returnPostedData)
719
+ returnPostedData = false;
692
720
  const schema = await this.getTableSchema(tableName);
693
721
  let RETURN;
694
722
  if (!schema)
@@ -696,7 +724,7 @@ export default class Inibase {
696
724
  const idFilePath = join(this.folder, this.database, tableName, "id.inib");
697
725
  let [last_line_number, last_id] = (await File.isExists(idFilePath))
698
726
  ? Object.entries((await File.get(idFilePath, -1, "number", undefined, this.salt))[0] ??
699
- {})[0]?.map(Number) ?? [0, 0]
727
+ {})[0].map(Number) ?? [0, 0]
700
728
  : [0, 0];
701
729
  if (Utils.isArrayOfObjects(data))
702
730
  RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
@@ -716,10 +744,17 @@ export default class Inibase {
716
744
  const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), RETURN);
717
745
  last_line_number += 1;
718
746
  for await (const [path, content] of Object.entries(pathesContents))
719
- 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);
720
755
  if (returnPostedData)
721
756
  return this.get(tableName, Utils.isArrayOfObjects(RETURN)
722
- ? RETURN.map((data) => data.id)
757
+ ? RETURN.map((data) => Number(data.id))
723
758
  : RETURN.id, options, !Utils.isArrayOfObjects(data) // return only one item if data is not array of objects
724
759
  );
725
760
  }
@@ -738,7 +773,9 @@ export default class Inibase {
738
773
  if (Utils.isArrayOfObjects(data)) {
739
774
  if (!data.every((item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)))
740
775
  throw this.throwError("INVALID_ID");
741
- 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));
742
779
  }
743
780
  else if (data.hasOwnProperty("id")) {
744
781
  if (!Utils.isValidID(data.id))
@@ -821,6 +858,8 @@ export default class Inibase {
821
858
  if ((Array.isArray(where) && where.every(Utils.isValidID)) ||
822
859
  Utils.isValidID(where)) {
823
860
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
861
+ if (!lineNumbers)
862
+ return null;
824
863
  return this.delete(tableName, lineNumbers, where);
825
864
  }
826
865
  else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
@@ -829,7 +868,7 @@ export default class Inibase {
829
868
  const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
830
869
  if (files.length) {
831
870
  if (!_id)
832
- _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));
833
872
  if (!_id.length)
834
873
  throw this.throwError("NO_ITEMS", tableName);
835
874
  for await (const file of files)
@@ -849,7 +888,7 @@ export default class Inibase {
849
888
  return null;
850
889
  }
851
890
  async sum(tableName, columns, where) {
852
- let RETURN;
891
+ let RETURN = {};
853
892
  const schema = await this.getTableSchema(tableName);
854
893
  if (!schema)
855
894
  throw this.throwError("NO_SCHEMA", tableName);
@@ -862,7 +901,9 @@ export default class Inibase {
862
901
  if (await File.isExists(columnPath)) {
863
902
  if (where) {
864
903
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
865
- RETURN[column] = await File.sum(columnPath, lineNumbers);
904
+ RETURN[column] = lineNumbers
905
+ ? await File.sum(columnPath, lineNumbers)
906
+ : 0;
866
907
  }
867
908
  else
868
909
  RETURN[column] = await File.sum(columnPath);
@@ -871,7 +912,7 @@ export default class Inibase {
871
912
  return Array.isArray(columns) ? RETURN : Object.values(RETURN)[0];
872
913
  }
873
914
  async max(tableName, columns, where) {
874
- let RETURN;
915
+ let RETURN = {};
875
916
  const schema = await this.getTableSchema(tableName);
876
917
  if (!schema)
877
918
  throw this.throwError("NO_SCHEMA", tableName);
@@ -884,7 +925,9 @@ export default class Inibase {
884
925
  if (await File.isExists(columnPath)) {
885
926
  if (where) {
886
927
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
887
- RETURN[column] = await File.max(columnPath, lineNumbers);
928
+ RETURN[column] = lineNumbers
929
+ ? await File.max(columnPath, lineNumbers)
930
+ : 0;
888
931
  }
889
932
  else
890
933
  RETURN[column] = await File.max(columnPath);
@@ -893,7 +936,7 @@ export default class Inibase {
893
936
  return RETURN;
894
937
  }
895
938
  async min(tableName, columns, where) {
896
- let RETURN;
939
+ let RETURN = {};
897
940
  const schema = await this.getTableSchema(tableName);
898
941
  if (!schema)
899
942
  throw this.throwError("NO_SCHEMA", tableName);
@@ -906,7 +949,9 @@ export default class Inibase {
906
949
  if (await File.isExists(columnPath)) {
907
950
  if (where) {
908
951
  const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
909
- RETURN[column] = await File.min(columnPath, lineNumbers);
952
+ RETURN[column] = lineNumbers
953
+ ? await File.min(columnPath, lineNumbers)
954
+ : 0;
910
955
  }
911
956
  else
912
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
  };
@@ -5,12 +5,12 @@ export declare const comparePassword: (hashedPassword: string, inputPassword: st
5
5
  export declare const encodeID: (id: number | string, secretKeyOrSalt: string | number | Buffer) => string;
6
6
  export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
7
7
  export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
8
- export declare const addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
8
+ export declare const addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
9
9
  export default class UtilsServer {
10
10
  static encodeID: (id: string | number, secretKeyOrSalt: string | number | Buffer) => string;
11
11
  static decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
12
12
  static hashPassword: (password: string) => string;
13
13
  static comparePassword: (hashedPassword: string, inputPassword: string) => boolean;
14
14
  static findLastIdNumber: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number;
15
- static addIdToSchema: (schema: Schema, oldIndex: number, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
15
+ static addIdToSchema: (schema: Schema, oldIndex: number | undefined, secretKeyOrSalt: string | number | Buffer) => import("./index.js").Field[];
16
16
  }