inibase 1.0.0-rc.17 → 1.0.0-rc.19

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/file.js CHANGED
@@ -1,4 +1,4 @@
1
- import { open, stat, writeFile } from "node:fs/promises";
1
+ import { open, rename, stat, writeFile } from "node:fs/promises";
2
2
  import { createInterface } from "node:readline";
3
3
  import { detectFieldType, isArrayOfArrays, isNumber } from "./utils.js";
4
4
  import { encodeID, comparePassword } from "./utils.server.js";
@@ -51,7 +51,7 @@ export const encode = (input, secretKey) => {
51
51
  ? joinMultidimensionalArray(secureArray(input))
52
52
  : secureString(input);
53
53
  };
54
- const unSecureString = (input) => decodeURIComponent(input)
54
+ const unSecureString = (input) => input
55
55
  .replaceAll("&lt;", "<")
56
56
  .replaceAll("&gt;", ">")
57
57
  .replaceAll("%2C", ",")
@@ -93,11 +93,11 @@ const decodeHelper = (value, fieldType, fieldChildrenType, secretKey) => {
93
93
  if (!Array.isArray(value))
94
94
  return [value];
95
95
  if (fieldChildrenType)
96
- return value.map((v) => decode(v, Array.isArray(fieldChildrenType)
97
- ? detectFieldType(v, fieldChildrenType)
98
- : fieldChildrenType, undefined, secretKey));
99
- else
100
- return value;
96
+ return fieldChildrenType
97
+ ? value.map((v) => decode(v, Array.isArray(fieldChildrenType)
98
+ ? detectFieldType(v, fieldChildrenType)
99
+ : fieldChildrenType, undefined, secretKey))
100
+ : value;
101
101
  case "id":
102
102
  return isNumber(value) ? encodeID(value, secretKey) : value;
103
103
  default:
@@ -119,9 +119,9 @@ export const decode = (input, fieldType, fieldChildrenType, secretKey) => {
119
119
  };
120
120
  export const get = async (filePath, lineNumbers, fieldType, fieldChildrenType, secretKey) => {
121
121
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
122
- ? fileHandle.readLines()
122
+ ? fileHandle.readLines({ autoClose: false })
123
123
  : createInterface({
124
- input: fileHandle.createReadStream(),
124
+ input: fileHandle.createReadStream({ autoClose: false }),
125
125
  crlfDelay: Infinity,
126
126
  });
127
127
  let lines = new Map(), lineCount = 0;
@@ -154,12 +154,12 @@ export const get = async (filePath, lineNumbers, fieldType, fieldChildrenType, s
154
154
  };
155
155
  export const replace = async (filePath, replacements) => {
156
156
  if (await isExists(filePath)) {
157
- const fileHandle = await open(filePath, "r+"), rl = doesSupportReadLines()
157
+ const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
158
158
  ? fileHandle.readLines({ autoClose: false })
159
159
  : createInterface({
160
160
  input: fileHandle.createReadStream({ autoClose: false }),
161
161
  crlfDelay: Infinity,
162
- }), writeStream = fileHandle.createWriteStream();
162
+ }), fileTempPath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`, fileTempHandle = await open(fileTempPath, "w+"), writeStream = fileTempHandle.createWriteStream({ autoClose: false });
163
163
  if (typeof replacements === "object" && !Array.isArray(replacements)) {
164
164
  if (!(replacements instanceof Map))
165
165
  replacements = new Map(Object.entries(replacements));
@@ -181,7 +181,10 @@ export const replace = async (filePath, replacements) => {
181
181
  else
182
182
  for await (const _line of rl)
183
183
  writeStream.write(replacements + "\n");
184
- writeStream.end(async () => await fileHandle.close());
184
+ // writeStream.end(async () => await rename(fileTempPath, filePath));
185
+ await fileHandle.close();
186
+ await fileTempHandle.close();
187
+ await rename(fileTempPath, filePath);
185
188
  }
186
189
  else if (typeof replacements === "object" && !Array.isArray(replacements)) {
187
190
  if (!(replacements instanceof Map))
@@ -195,7 +198,7 @@ export const replace = async (filePath, replacements) => {
195
198
  };
196
199
  export const append = async (filePath, data, startsAt = 1) => {
197
200
  const doesFileExists = await isExists(filePath);
198
- const fileHandle = await open(filePath, "a"), writeStream = fileHandle.createWriteStream();
201
+ const fileHandle = await open(filePath, "a"), writeStream = fileHandle.createWriteStream({ autoClose: false });
199
202
  if (doesFileExists) {
200
203
  const currentNumberOfLines = await count(filePath);
201
204
  if (startsAt - currentNumberOfLines - 1 > 0)
@@ -221,25 +224,28 @@ export const append = async (filePath, data, startsAt = 1) => {
221
224
  };
222
225
  export const remove = async (filePath, linesToDelete) => {
223
226
  let lineCount = 0;
224
- const linesToDeleteArray = new Set(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]), fileHandle = await open(filePath, "r+"), rl = doesSupportReadLines()
227
+ const linesToDeleteArray = new Set(Array.isArray(linesToDelete) ? linesToDelete : [linesToDelete]), fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
225
228
  ? fileHandle.readLines({ autoClose: false })
226
229
  : createInterface({
227
230
  input: fileHandle.createReadStream({ autoClose: false }),
228
231
  crlfDelay: Infinity,
229
- }), writeStream = fileHandle.createWriteStream();
232
+ }), fileTempPath = `${filePath.replace(".inib", "")}-${Date.now()}.tmp`, fileTempHandle = await open(fileTempPath, "w+"), writeStream = fileTempHandle.createWriteStream({ autoClose: false });
230
233
  for await (const line of rl) {
231
234
  lineCount++;
232
235
  if (!linesToDeleteArray.has(lineCount))
233
236
  writeStream.write(`${line}\n`);
234
237
  }
235
- writeStream.end(async () => await fileHandle.close()); // Rename the temp file to the original file name
238
+ // writeStream.end(async () => await rename(fileTempPath, filePath));
239
+ await fileHandle.close();
240
+ await fileTempHandle.close();
241
+ await rename(fileTempPath, filePath);
236
242
  };
237
243
  export const count = async (filePath) => {
238
244
  let lineCount = 0;
239
245
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
240
- ? fileHandle.readLines()
246
+ ? fileHandle.readLines({ autoClose: false })
241
247
  : createInterface({
242
- input: fileHandle.createReadStream(),
248
+ input: fileHandle.createReadStream({ autoClose: false }),
243
249
  crlfDelay: Infinity,
244
250
  });
245
251
  for await (const line of rl)
@@ -301,9 +307,9 @@ const handleComparisonOperator = (operator, originalValue, comparedAtValue, fiel
301
307
  export const search = async (filePath, operator, comparedAtValue, logicalOperator, fieldType, fieldChildrenType, limit, offset, readWholeFile, secretKey) => {
302
308
  let RETURN = new Map(), lineCount = 0, foundItems = 0;
303
309
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
304
- ? fileHandle.readLines()
310
+ ? fileHandle.readLines({ autoClose: false })
305
311
  : createInterface({
306
- input: fileHandle.createReadStream(),
312
+ input: fileHandle.createReadStream({ autoClose: false }),
307
313
  crlfDelay: Infinity,
308
314
  });
309
315
  for await (const line of rl) {
@@ -335,9 +341,9 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
335
341
  };
336
342
  export const sum = async (filePath, lineNumbers) => {
337
343
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
338
- ? fileHandle.readLines()
344
+ ? fileHandle.readLines({ autoClose: false })
339
345
  : createInterface({
340
- input: fileHandle.createReadStream(),
346
+ input: fileHandle.createReadStream({ autoClose: false }),
341
347
  crlfDelay: Infinity,
342
348
  });
343
349
  let sum = 0;
@@ -357,14 +363,13 @@ export const sum = async (filePath, lineNumbers) => {
357
363
  else
358
364
  for await (const line of rl)
359
365
  sum += +decode(line, "number");
360
- await fileHandle.close();
361
366
  return sum;
362
367
  };
363
368
  export const max = async (filePath, lineNumbers) => {
364
369
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
365
- ? fileHandle.readLines()
370
+ ? fileHandle.readLines({ autoClose: false })
366
371
  : createInterface({
367
- input: fileHandle.createReadStream(),
372
+ input: fileHandle.createReadStream({ autoClose: false }),
368
373
  crlfDelay: Infinity,
369
374
  });
370
375
  let max = 0;
@@ -389,14 +394,13 @@ export const max = async (filePath, lineNumbers) => {
389
394
  if (lineContentNum > max)
390
395
  max = lineContentNum;
391
396
  }
392
- await fileHandle.close();
393
397
  return max;
394
398
  };
395
399
  export const min = async (filePath, lineNumbers) => {
396
400
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
397
- ? fileHandle.readLines()
401
+ ? fileHandle.readLines({ autoClose: false })
398
402
  : createInterface({
399
- input: fileHandle.createReadStream(),
403
+ input: fileHandle.createReadStream({ autoClose: false }),
400
404
  crlfDelay: Infinity,
401
405
  });
402
406
  let min = 0;
@@ -421,21 +425,18 @@ export const min = async (filePath, lineNumbers) => {
421
425
  if (lineContentNum < min)
422
426
  min = lineContentNum;
423
427
  }
424
- await fileHandle.close();
425
428
  return min;
426
429
  };
427
430
  export const sort = async (filePath, sortDirection, lineNumbers, _lineNumbersPerChunk = 100000) => {
428
431
  const fileHandle = await open(filePath, "r"), rl = doesSupportReadLines()
429
- ? fileHandle.readLines()
432
+ ? fileHandle.readLines({ autoClose: false })
430
433
  : createInterface({
431
- input: fileHandle.createReadStream(),
434
+ input: fileHandle.createReadStream({ autoClose: false }),
432
435
  crlfDelay: Infinity,
433
436
  });
434
437
  let lineCount = 0;
435
- for await (const line of rl) {
438
+ for await (const line of rl)
436
439
  lineCount++;
437
- }
438
- await fileHandle.close();
439
440
  };
440
441
  export default class File {
441
442
  static get = get;
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@
2
2
  export interface Data {
3
3
  id?: number | string;
4
4
  [key: string]: any;
5
- createdAt?: Date;
6
- updatedAt?: Date;
5
+ createdAt?: number;
6
+ updatedAt?: number;
7
7
  }
8
8
  export type FieldType = "string" | "number" | "boolean" | "date" | "email" | "url" | "table" | "object" | "array" | "password" | "html" | "ip" | "id";
9
9
  type FieldDefault = {
@@ -73,10 +73,17 @@ export default class Inibase {
73
73
  formatData<dataType extends Data | Data[]>(data: dataType, schema: Schema, formatOnlyAvailiableKeys?: boolean): dataType extends Data ? Data : Data[];
74
74
  private getDefaultValue;
75
75
  private joinPathesContents;
76
+ private getItemsFromSchema;
77
+ private FormatObjectCriteriaValue;
78
+ private applyCriteria;
76
79
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined): Promise<Data | null>;
77
80
  get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true): Promise<number[] | null>;
78
- post<DataType extends Data | Data[]>(tableName: string, data: DataType, options?: Options, returnPostedData?: boolean): Promise<DataType extends Data ? Data | null | void : Data[] | null | void>;
79
- put<returnPostedDataType extends boolean = true>(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: returnPostedDataType): Promise<(returnPostedDataType extends true ? Data | Data[] : void) | null>;
81
+ post(tableName: string, data: Data | Data[], options: Options | undefined, returnPostedData?: false): Promise<void | null>;
82
+ post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
83
+ 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, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
86
+ put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
80
87
  delete(tableName: string, where?: number | string | (number | string)[] | Criteria, _id?: string | string[]): Promise<string | string[] | null>;
81
88
  sum(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
82
89
  sum(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
package/dist/index.js CHANGED
@@ -291,6 +291,304 @@ export default class Inibase {
291
291
  File.encode(value, this.salt),
292
292
  ]));
293
293
  }
294
+ async getItemsFromSchema(tableName, schema, linesNumber, options, prefix) {
295
+ const path = join(this.folder, this.database, tableName);
296
+ let RETURN = {};
297
+ for (const field of schema) {
298
+ if ((field.type === "array" ||
299
+ (Array.isArray(field.type) &&
300
+ field.type.includes("array"))) &&
301
+ field.children) {
302
+ if (Utils.isArrayOfObjects(field.children)) {
303
+ if (field.children.filter((children) => children.type === "array" &&
304
+ Utils.isArrayOfObjects(children.children)).length) {
305
+ // one of children has array field type and has children array of object = Schema
306
+ Object.entries((await this.getItemsFromSchema(tableName, field.children.filter((children) => children.type === "array" &&
307
+ Utils.isArrayOfObjects(children.children)), linesNumber, options, (prefix ?? "") + field.key + ".")) ?? {}).forEach(([index, item]) => {
308
+ if (Utils.isObject(item)) {
309
+ if (!RETURN[index])
310
+ RETURN[index] = {};
311
+ if (!RETURN[index][field.key])
312
+ RETURN[index][field.key] = [];
313
+ for (const child_field of field.children.filter((children) => children.type === "array" &&
314
+ Utils.isArrayOfObjects(children.children))) {
315
+ if (Utils.isObject(item[child_field.key])) {
316
+ Object.entries(item[child_field.key]).forEach(([key, value]) => {
317
+ if (!Utils.isArrayOfArrays(value))
318
+ value = value.map((_value) => child_field.type === "array" ? [[_value]] : [_value]);
319
+ for (let _i = 0; _i < value.length; _i++) {
320
+ if (Utils.isArrayOfNulls(value[_i]))
321
+ continue;
322
+ if (!RETURN[index][field.key][_i])
323
+ RETURN[index][field.key][_i] = {};
324
+ if (!RETURN[index][field.key][_i][child_field.key])
325
+ RETURN[index][field.key][_i][child_field.key] = [];
326
+ value[_i].forEach((_element, _index) => {
327
+ if (!RETURN[index][field.key][_i][child_field.key][_index])
328
+ RETURN[index][field.key][_i][child_field.key][_index] = {};
329
+ RETURN[index][field.key][_i][child_field.key][_index][key] = _element;
330
+ });
331
+ }
332
+ });
333
+ }
334
+ }
335
+ }
336
+ });
337
+ field.children = field.children.filter((children) => children.type !== "array" ||
338
+ !Utils.isArrayOfObjects(children.children));
339
+ }
340
+ Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, (prefix ?? "") + field.key + ".")) ?? {}).forEach(([index, item]) => {
341
+ if (!RETURN[index])
342
+ RETURN[index] = {};
343
+ if (Utils.isObject(item)) {
344
+ if (!Object.values(item).every((i) => i === null)) {
345
+ if (RETURN[index][field.key]) {
346
+ Object.entries(item).forEach(([key, value], _index) => {
347
+ RETURN[index][field.key] = RETURN[index][field.key].map((_obj, _i) => ({
348
+ ..._obj,
349
+ [key]: value[_i],
350
+ }));
351
+ });
352
+ }
353
+ else if (Object.values(item).every((_i) => Utils.isArrayOfArrays(_i) || Array.isArray(_i)))
354
+ RETURN[index][field.key] = item;
355
+ else {
356
+ RETURN[index][field.key] = [];
357
+ Object.entries(item).forEach(([key, value]) => {
358
+ for (let _i = 0; _i < value.length; _i++) {
359
+ if (value[_i] === null ||
360
+ (Array.isArray(value[_i]) &&
361
+ value[_i].every((_item) => _item === null)))
362
+ continue;
363
+ if (!RETURN[index][field.key][_i])
364
+ RETURN[index][field.key][_i] = {};
365
+ RETURN[index][field.key][_i][key] = value[_i];
366
+ }
367
+ });
368
+ }
369
+ }
370
+ else
371
+ RETURN[index][field.key] = null;
372
+ }
373
+ else
374
+ RETURN[index][field.key] = item;
375
+ });
376
+ }
377
+ else if (field.children === "table" ||
378
+ (Array.isArray(field.children) && field.children.includes("table"))) {
379
+ if (options.columns)
380
+ options.columns = options.columns
381
+ .filter((column) => column.includes(`${field.key}.`))
382
+ .map((column) => column.replace(`${field.key}.`, ""));
383
+ const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
384
+ this.totalItems[tableName + "-" + field.key] = total_lines;
385
+ for (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
+ }
392
+ }
393
+ else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
394
+ const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
395
+ 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
+ }
401
+ }
402
+ }
403
+ else if (field.type === "object") {
404
+ for (const [index, item] of Object.entries((await this.getItemsFromSchema(tableName, field.children, linesNumber, options, (prefix ?? "") + field.key + ".")) ?? {})) {
405
+ if (!RETURN[index])
406
+ RETURN[index] = {};
407
+ if (Utils.isObject(item)) {
408
+ if (!Object.values(item).every((i) => i === null))
409
+ RETURN[index][field.key] = item;
410
+ else
411
+ RETURN[index][field.key] = null;
412
+ }
413
+ else
414
+ RETURN[index][field.key] = null;
415
+ }
416
+ }
417
+ else if (field.type === "table") {
418
+ if ((await File.isExists(join(this.folder, this.database, field.key))) &&
419
+ (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib")))) {
420
+ if (options.columns)
421
+ options.columns = options.columns
422
+ .filter((column) => column.includes(`${field.key}.`) &&
423
+ !column.includes(`${field.key}.`))
424
+ .map((column) => column.replace(`${field.key}.`, ""));
425
+ const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
426
+ this.totalItems[tableName + "-" + field.key] = total_lines;
427
+ for (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
+ }
434
+ }
435
+ }
436
+ else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
437
+ const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
438
+ 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
+ }
444
+ }
445
+ }
446
+ return RETURN;
447
+ }
448
+ FormatObjectCriteriaValue(value, isParentArray = false) {
449
+ switch (value[0]) {
450
+ case ">":
451
+ case "<":
452
+ case "[":
453
+ return ["=", "]", "*"].includes(value[1])
454
+ ? [
455
+ value.slice(0, 2),
456
+ value.slice(2),
457
+ ]
458
+ : [
459
+ value.slice(0, 1),
460
+ value.slice(1),
461
+ ];
462
+ case "!":
463
+ return ["=", "*"].includes(value[1])
464
+ ? [
465
+ value.slice(0, 2),
466
+ value.slice(2),
467
+ ]
468
+ : value[1] === "["
469
+ ? [
470
+ value.slice(0, 3),
471
+ value.slice(3),
472
+ ]
473
+ : [
474
+ (value.slice(0, 1) + "="),
475
+ value.slice(1),
476
+ ];
477
+ case "=":
478
+ return isParentArray
479
+ ? [
480
+ value.slice(0, 1),
481
+ value.slice(1),
482
+ ]
483
+ : [
484
+ value.slice(0, 1),
485
+ (value.slice(1) + ","),
486
+ ];
487
+ case "*":
488
+ return [
489
+ value.slice(0, 1),
490
+ value.slice(1),
491
+ ];
492
+ default:
493
+ return ["=", value];
494
+ }
495
+ }
496
+ async applyCriteria(tableName, schema, options, criteria, allTrue) {
497
+ let RETURN = {};
498
+ if (!criteria)
499
+ return null;
500
+ if (criteria.and && Utils.isObject(criteria.and)) {
501
+ const searchResult = await this.applyCriteria(tableName, schema, options, criteria.and, true);
502
+ if (searchResult) {
503
+ RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).filter(([_k, v], _i) => Object.keys(v).length === Object.keys(criteria.and ?? {}).length)));
504
+ delete criteria.and;
505
+ }
506
+ else
507
+ return null;
508
+ }
509
+ if (criteria.or && Utils.isObject(criteria.or)) {
510
+ const searchResult = await this.applyCriteria(tableName, schema, options, criteria.or, false);
511
+ delete criteria.or;
512
+ if (searchResult)
513
+ RETURN = Utils.deepMerge(RETURN, searchResult);
514
+ }
515
+ if (Object.keys(criteria).length > 0) {
516
+ if (allTrue === undefined)
517
+ allTrue = true;
518
+ let index = -1;
519
+ for (const [key, value] of Object.entries(criteria)) {
520
+ const field = this.getField(key, schema);
521
+ index++;
522
+ let searchOperator = undefined, searchComparedAtValue = undefined, searchLogicalOperator = undefined;
523
+ if (Utils.isObject(value)) {
524
+ if (value?.or &&
525
+ Array.isArray(value.or)) {
526
+ const searchCriteria = value.or
527
+ .map((single_or) => typeof single_or === "string"
528
+ ? this.FormatObjectCriteriaValue(single_or)
529
+ : ["=", single_or])
530
+ .filter((a) => a);
531
+ if (searchCriteria.length > 0) {
532
+ searchOperator = searchCriteria.map((single_or) => single_or[0]);
533
+ searchComparedAtValue = searchCriteria.map((single_or) => single_or[1]);
534
+ searchLogicalOperator = "or";
535
+ }
536
+ delete value.or;
537
+ }
538
+ if (value?.and &&
539
+ Array.isArray(value.and)) {
540
+ const searchCriteria = value.and
541
+ .map((single_and) => typeof single_and === "string"
542
+ ? this.FormatObjectCriteriaValue(single_and)
543
+ : ["=", single_and])
544
+ .filter((a) => a);
545
+ if (searchCriteria.length > 0) {
546
+ searchOperator = searchCriteria.map((single_and) => single_and[0]);
547
+ searchComparedAtValue = searchCriteria.map((single_and) => single_and[1]);
548
+ searchLogicalOperator = "and";
549
+ }
550
+ delete value.and;
551
+ }
552
+ }
553
+ else if (Array.isArray(value)) {
554
+ const searchCriteria = value
555
+ .map((single) => typeof single === "string"
556
+ ? this.FormatObjectCriteriaValue(single)
557
+ : ["=", single])
558
+ .filter((a) => a);
559
+ if (searchCriteria.length > 0) {
560
+ searchOperator = searchCriteria.map((single) => single[0]);
561
+ searchComparedAtValue = searchCriteria.map((single) => single[1]);
562
+ searchLogicalOperator = "and";
563
+ }
564
+ }
565
+ else if (typeof value === "string") {
566
+ const ComparisonOperatorValue = this.FormatObjectCriteriaValue(value);
567
+ if (ComparisonOperatorValue) {
568
+ searchOperator = ComparisonOperatorValue[0];
569
+ searchComparedAtValue = ComparisonOperatorValue[1];
570
+ }
571
+ }
572
+ else {
573
+ searchOperator = "=";
574
+ searchComparedAtValue = value;
575
+ }
576
+ 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);
577
+ if (searchResult) {
578
+ RETURN = Utils.deepMerge(RETURN, searchResult);
579
+ this.totalItems[tableName + "-" + key] = total_lines;
580
+ }
581
+ if (allTrue && index > 0) {
582
+ if (!Object.keys(RETURN).length)
583
+ RETURN = {};
584
+ RETURN = Object.fromEntries(Object.entries(RETURN).filter(([_index, item]) => Object.keys(item).length > index));
585
+ if (!Object.keys(RETURN).length)
586
+ RETURN = {};
587
+ }
588
+ }
589
+ }
590
+ return Object.keys(RETURN).length ? RETURN : null;
591
+ }
294
592
  async get(tableName, where, options = {
295
593
  page: 1,
296
594
  per_page: 15,
@@ -333,166 +631,11 @@ export default class Inibase {
333
631
  .filter((i) => i);
334
632
  if (options.columns.length)
335
633
  schema = filterSchemaByColumns(schema, options.columns);
336
- const getItemsFromSchema = async (path, schema, linesNumber, prefix) => {
337
- let RETURN = {};
338
- for (const field of schema) {
339
- if ((field.type === "array" ||
340
- (Array.isArray(field.type) &&
341
- field.type.includes("array"))) &&
342
- field
343
- .children) {
344
- if (Utils.isArrayOfObjects(field
345
- .children)) {
346
- if (field
347
- .children.filter((children) => children.type === "array" &&
348
- Utils.isArrayOfObjects(children.children)).length) {
349
- // one of children has array field type and has children array of object = Schema
350
- Object.entries((await getItemsFromSchema(path, field.children.filter((children) => children.type === "array" &&
351
- Utils.isArrayOfObjects(children.children)), linesNumber, (prefix ?? "") + field.key + ".")) ?? {}).forEach(([index, item]) => {
352
- if (Utils.isObject(item)) {
353
- if (!RETURN[index])
354
- RETURN[index] = {};
355
- if (!RETURN[index][field.key])
356
- RETURN[index][field.key] = [];
357
- for (const child_field of field.children.filter((children) => children.type === "array" &&
358
- Utils.isArrayOfObjects(children.children))) {
359
- if (Utils.isObject(item[child_field.key])) {
360
- Object.entries(item[child_field.key]).forEach(([key, value]) => {
361
- for (let _i = 0; _i < value.length; _i++) {
362
- if (!RETURN[index][field.key][_i])
363
- RETURN[index][field.key][_i] = {};
364
- if (!RETURN[index][field.key][_i][child_field.key])
365
- RETURN[index][field.key][_i][child_field.key] =
366
- [];
367
- value[_i].forEach((_element, _index) => {
368
- if (!RETURN[index][field.key][_i][child_field.key][_index])
369
- RETURN[index][field.key][_i][child_field.key][_index] = {};
370
- RETURN[index][field.key][_i][child_field.key][_index][key] = _element;
371
- });
372
- }
373
- });
374
- }
375
- }
376
- }
377
- });
378
- field.children = field
379
- .children.filter((children) => children.type !== "array" ||
380
- !Utils.isArrayOfObjects(children.children));
381
- }
382
- Object.entries((await getItemsFromSchema(path, field
383
- .children, linesNumber, (prefix ?? "") + field.key + ".")) ?? {}).forEach(([index, item]) => {
384
- if (!RETURN[index])
385
- RETURN[index] = {};
386
- if (Utils.isObject(item)) {
387
- if (!Object.values(item).every((i) => i === null)) {
388
- if (RETURN[index][field.key])
389
- Object.entries(item).forEach(([key, value], _index) => {
390
- RETURN[index][field.key] = RETURN[index][field.key].map((_obj, _i) => ({
391
- ..._obj,
392
- [key]: value[_i],
393
- }));
394
- });
395
- else if (Object.values(item).every(Utils.isArrayOfArrays))
396
- RETURN[index][field.key] = item;
397
- else {
398
- RETURN[index][field.key] = [];
399
- Object.entries(item).forEach(([key, value]) => {
400
- for (let _i = 0; _i < value.length; _i++) {
401
- if (!RETURN[index][field.key][_i])
402
- RETURN[index][field.key][_i] = {};
403
- RETURN[index][field.key][_i][key] = value[_i];
404
- }
405
- });
406
- }
407
- }
408
- else
409
- RETURN[index][field.key] = null;
410
- }
411
- else
412
- RETURN[index][field.key] = item;
413
- });
414
- }
415
- else if (field
416
- .children === "table" ||
417
- (Array.isArray(field
418
- .children) &&
419
- field
420
- .children.includes("table"))) {
421
- if (options.columns)
422
- options.columns = options.columns
423
- .filter((column) => column.includes(`${field.key}.`))
424
- .map((column) => column.replace(`${field.key}.`, ""));
425
- const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field
426
- .children, this.salt);
427
- this.totalItems[tableName + "-" + field.key] = total_lines;
428
- for (const [index, item] of Object.entries(items)) {
429
- if (!RETURN[index])
430
- RETURN[index] = {};
431
- RETURN[index][field.key] = item
432
- ? await this.get(field.key, item, options)
433
- : this.getDefaultValue(field);
434
- }
435
- }
436
- else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
437
- const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
438
- 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
- }
444
- }
445
- }
446
- else if (field.type === "object") {
447
- for (const [index, item] of Object.entries((await getItemsFromSchema(path, field.children, linesNumber, (prefix ?? "") + field.key + ".")) ?? {})) {
448
- if (!RETURN[index])
449
- RETURN[index] = {};
450
- if (Utils.isObject(item)) {
451
- if (!Object.values(item).every((i) => i === null))
452
- RETURN[index][field.key] = item;
453
- else
454
- RETURN[index][field.key] = null;
455
- }
456
- else
457
- RETURN[index][field.key] = null;
458
- }
459
- }
460
- else if (field.type === "table") {
461
- if ((await File.isExists(join(this.folder, this.database, field.key))) &&
462
- (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib")))) {
463
- if (options.columns)
464
- options.columns = options.columns
465
- .filter((column) => column.includes(`${field.key}.`) &&
466
- !column.includes(`${field.key}.`))
467
- .map((column) => column.replace(`${field.key}.`, ""));
468
- const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
469
- this.totalItems[tableName + "-" + field.key] = total_lines;
470
- for (const [index, item] of Object.entries(items)) {
471
- if (!RETURN[index])
472
- RETURN[index] = {};
473
- RETURN[index][field.key] = item
474
- ? await this.get(field.key, item, options)
475
- : this.getDefaultValue(field);
476
- }
477
- }
478
- }
479
- else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
480
- const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
481
- this.totalItems[tableName + "-" + field.key] = total_lines;
482
- for (const [index, item] of Object.entries(items)) {
483
- if (!RETURN[index])
484
- RETURN[index] = {};
485
- RETURN[index][field.key] = item ?? this.getDefaultValue(field);
486
- }
487
- }
488
- }
489
- return RETURN;
490
- };
491
634
  if (!where) {
492
635
  // Display all data
493
- RETURN = Object.values(await getItemsFromSchema(join(this.folder, this.database, tableName), schema, Array.from({ length: options.per_page }, (_, index) => (options.page - 1) * options.per_page +
636
+ RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.per_page }, (_, index) => (options.page - 1) * options.per_page +
494
637
  index +
495
- 1)));
638
+ 1), options));
496
639
  }
497
640
  else if ((Array.isArray(where) &&
498
641
  (where.every(Utils.isValidID) || where.every(Utils.isNumber))) ||
@@ -505,164 +648,21 @@ export default class Inibase {
505
648
  if (!lineNumbers)
506
649
  throw this.throwError("INVALID_ID", where);
507
650
  if (onlyLinesNumbers)
508
- return Object.keys(lineNumbers).map(Number);
509
- RETURN = Object.values((await getItemsFromSchema(join(this.folder, this.database, tableName), schema, Object.keys(lineNumbers).map(Number))) ?? {});
651
+ return Object.keys(lineNumbers).length
652
+ ? Object.keys(lineNumbers).map(Number)
653
+ : null;
654
+ RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
510
655
  if (RETURN.length && !Array.isArray(where))
511
656
  RETURN = RETURN[0];
512
657
  }
513
658
  else if (Utils.isObject(where)) {
514
659
  // Criteria
515
- const FormatObjectCriteriaValue = (value, isParentArray = false) => {
516
- switch (value[0]) {
517
- case ">":
518
- case "<":
519
- case "[":
520
- return ["=", "]", "*"].includes(value[1])
521
- ? [
522
- value.slice(0, 2),
523
- value.slice(2),
524
- ]
525
- : [
526
- value.slice(0, 1),
527
- value.slice(1),
528
- ];
529
- case "!":
530
- return ["=", "*"].includes(value[1])
531
- ? [
532
- value.slice(0, 2),
533
- value.slice(2),
534
- ]
535
- : value[1] === "["
536
- ? [
537
- value.slice(0, 3),
538
- value.slice(3),
539
- ]
540
- : [
541
- (value.slice(0, 1) + "="),
542
- value.slice(1),
543
- ];
544
- case "=":
545
- return isParentArray
546
- ? [
547
- value.slice(0, 1),
548
- value.slice(1),
549
- ]
550
- : [
551
- value.slice(0, 1),
552
- (value.slice(1) + ","),
553
- ];
554
- case "*":
555
- return [
556
- value.slice(0, 1),
557
- value.slice(1),
558
- ];
559
- default:
560
- return ["=", value];
561
- }
562
- };
563
- const applyCriteria = async (criteria, allTrue) => {
564
- let RETURN = {};
565
- if (!criteria)
566
- return null;
567
- if (criteria.and && Utils.isObject(criteria.and)) {
568
- const searchResult = await applyCriteria(criteria.and, true);
569
- if (searchResult) {
570
- RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).filter(([_k, v], _i) => Object.keys(v).length ===
571
- Object.keys(criteria.and ?? {}).length)));
572
- delete criteria.and;
573
- }
574
- else
575
- return null;
576
- }
577
- if (criteria.or && Utils.isObject(criteria.or)) {
578
- const searchResult = await applyCriteria(criteria.or, false);
579
- delete criteria.or;
580
- if (searchResult)
581
- RETURN = Utils.deepMerge(RETURN, searchResult);
582
- }
583
- if (Object.keys(criteria).length > 0) {
584
- if (allTrue === undefined)
585
- allTrue = true;
586
- let index = -1;
587
- for (const [key, value] of Object.entries(criteria)) {
588
- const field = this.getField(key, schema);
589
- index++;
590
- let searchOperator = undefined, searchComparedAtValue = undefined, searchLogicalOperator = undefined;
591
- if (Utils.isObject(value)) {
592
- if (value?.or &&
593
- Array.isArray(value.or)) {
594
- const searchCriteria = value.or
595
- .map((single_or) => typeof single_or === "string"
596
- ? FormatObjectCriteriaValue(single_or)
597
- : ["=", single_or])
598
- .filter((a) => a);
599
- if (searchCriteria.length > 0) {
600
- searchOperator = searchCriteria.map((single_or) => single_or[0]);
601
- searchComparedAtValue = searchCriteria.map((single_or) => single_or[1]);
602
- searchLogicalOperator = "or";
603
- }
604
- delete value.or;
605
- }
606
- if (value?.and &&
607
- Array.isArray(value.and)) {
608
- const searchCriteria = value.and
609
- .map((single_and) => typeof single_and === "string"
610
- ? FormatObjectCriteriaValue(single_and)
611
- : ["=", single_and])
612
- .filter((a) => a);
613
- if (searchCriteria.length > 0) {
614
- searchOperator = searchCriteria.map((single_and) => single_and[0]);
615
- searchComparedAtValue = searchCriteria.map((single_and) => single_and[1]);
616
- searchLogicalOperator = "and";
617
- }
618
- delete value.and;
619
- }
620
- }
621
- else if (Array.isArray(value)) {
622
- const searchCriteria = value
623
- .map((single) => typeof single === "string"
624
- ? FormatObjectCriteriaValue(single)
625
- : ["=", single])
626
- .filter((a) => a);
627
- if (searchCriteria.length > 0) {
628
- searchOperator = searchCriteria.map((single) => single[0]);
629
- searchComparedAtValue = searchCriteria.map((single) => single[1]);
630
- searchLogicalOperator = "and";
631
- }
632
- }
633
- else if (typeof value === "string") {
634
- const ComparisonOperatorValue = FormatObjectCriteriaValue(value);
635
- if (ComparisonOperatorValue) {
636
- searchOperator = ComparisonOperatorValue[0];
637
- searchComparedAtValue = ComparisonOperatorValue[1];
638
- }
639
- }
640
- else {
641
- searchOperator = "=";
642
- searchComparedAtValue = value;
643
- }
644
- 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);
645
- if (searchResult) {
646
- RETURN = Utils.deepMerge(RETURN, searchResult);
647
- this.totalItems[tableName + "-" + key] = total_lines;
648
- }
649
- if (allTrue && index > 0) {
650
- if (!Object.keys(RETURN).length)
651
- RETURN = {};
652
- RETURN = Object.fromEntries(Object.entries(RETURN).filter(([_index, item]) => Object.keys(item).length > index));
653
- if (!Object.keys(RETURN).length)
654
- RETURN = {};
655
- }
656
- }
657
- }
658
- return Object.keys(RETURN).length ? RETURN : null;
659
- };
660
- RETURN = await applyCriteria(where);
660
+ RETURN = await this.applyCriteria(tableName, schema, options, where);
661
661
  if (RETURN) {
662
662
  if (onlyLinesNumbers)
663
663
  return Object.keys(RETURN).map(Number);
664
664
  const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]).map((key) => parse(key).name);
665
- RETURN = Object.values(Utils.deepMerge(RETURN, await getItemsFromSchema(join(this.folder, this.database, tableName), schema.filter((field) => !alreadyExistsColumns.includes(field.key)), Object.keys(RETURN).map(Number))));
665
+ RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter((field) => !alreadyExistsColumns.includes(field.key)), Object.keys(RETURN).map(Number), options)));
666
666
  }
667
667
  }
668
668
  if (!RETURN ||
@@ -695,13 +695,13 @@ export default class Inibase {
695
695
  RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
696
696
  id: ++last_id,
697
697
  ...rest,
698
- createdAt: new Date(),
698
+ createdAt: new Date().getTime(),
699
699
  }));
700
700
  else
701
701
  RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
702
702
  id: ++last_id,
703
703
  ...rest,
704
- createdAt: new Date(),
704
+ createdAt: new Date().getTime(),
705
705
  }))(data);
706
706
  if (!RETURN)
707
707
  throw this.throwError("NO_DATA");
@@ -742,11 +742,11 @@ export default class Inibase {
742
742
  const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), Utils.isArrayOfObjects(data)
743
743
  ? data.map((item) => ({
744
744
  ...(({ id, ...restOfData }) => restOfData)(item),
745
- updatedAt: new Date(),
745
+ updatedAt: new Date().getTime(),
746
746
  }))
747
747
  : {
748
748
  ...(({ id, ...restOfData }) => restOfData)(data),
749
- updatedAt: new Date(),
749
+ updatedAt: new Date().getTime(),
750
750
  });
751
751
  for await (const [path, content] of Object.entries(pathesContents))
752
752
  await File.replace(path, content);
@@ -769,9 +769,9 @@ export default class Inibase {
769
769
  const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(join(this.folder, this.database, tableName), Utils.isArrayOfObjects(data)
770
770
  ? data.map((item) => ({
771
771
  ...item,
772
- updatedAt: new Date(),
772
+ updatedAt: new Date().getTime(),
773
773
  }))
774
- : { ...data, updatedAt: new Date() })).map(([path, content]) => [
774
+ : { ...data, updatedAt: new Date().getTime() })).map(([path, content]) => [
775
775
  path,
776
776
  [...(Array.isArray(where) ? where : [where])].reduce((obj, lineNum, index) => ({
777
777
  ...obj,
@@ -784,9 +784,9 @@ export default class Inibase {
784
784
  return this.get(tableName, where, options, !Array.isArray(where));
785
785
  }
786
786
  }
787
- else if (typeof where === "object") {
788
- const lineNumbers = this.get(tableName, where, undefined, undefined, true);
789
- if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
787
+ else if (Utils.isObject(where)) {
788
+ const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
789
+ if (!lineNumbers || !lineNumbers.length)
790
790
  throw this.throwError("NO_ITEMS", tableName);
791
791
  return this.put(tableName, data, lineNumbers);
792
792
  }
@@ -823,16 +823,18 @@ export default class Inibase {
823
823
  const files = await readdir(join(this.folder, this.database, tableName));
824
824
  if (files.length) {
825
825
  if (!_id)
826
- _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));
826
+ _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));
827
+ if (!_id.length)
828
+ throw this.throwError("NO_ITEMS", tableName);
827
829
  for (const file of files.filter((fileName) => fileName.endsWith(".inib")))
828
830
  await File.remove(join(this.folder, this.database, tableName, file), where);
829
831
  return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
830
832
  }
831
833
  }
832
834
  }
833
- else if (typeof where === "object" && !Array.isArray(where)) {
834
- const lineNumbers = this.get(tableName, where, undefined, undefined, true);
835
- if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
835
+ else if (Utils.isObject(where)) {
836
+ const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
837
+ if (!lineNumbers || !lineNumbers.length)
836
838
  throw this.throwError("NO_ITEMS", tableName);
837
839
  return this.delete(tableName, lineNumbers);
838
840
  }
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  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
+ export declare const isArrayOfNulls: (input: any) => input is null[] | null[][];
4
5
  export declare const isObject: (obj: any) => boolean;
5
6
  export declare const deepMerge: (target: any, source: any) => any;
6
7
  export declare const combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
@@ -38,4 +39,5 @@ export default class Utils {
38
39
  static isIP: (input: any) => boolean;
39
40
  static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
40
41
  static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
42
+ static isArrayOfNulls: (input: any) => input is null[] | null[][];
41
43
  }
package/dist/utils.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export const isArrayOfObjects = (input) => Array.isArray(input) && (input.length === 0 || input.every(isObject));
2
2
  export const isArrayOfArrays = (input) => Array.isArray(input) && (input.length === 0 || input.every(Array.isArray));
3
+ export const isArrayOfNulls = (input) => input.every((_input) => Array.isArray(_input) ? isArrayOfNulls(_input) : _input === null);
3
4
  export const isObject = (obj) => obj != null &&
4
5
  (obj.constructor.name === "Object" ||
5
6
  (typeof obj === "object" && !Array.isArray(obj)));
@@ -21,8 +22,8 @@ export const combineObjects = (arr) => {
21
22
  if (obj.hasOwnProperty(key)) {
22
23
  const existingValue = result[key];
23
24
  const newValue = obj[key];
24
- if (typeof existingValue === "object" &&
25
- typeof newValue === "object" &&
25
+ if (isObject(existingValue) &&
26
+ isObject(newValue) &&
26
27
  existingValue !== null &&
27
28
  existingValue !== undefined &&
28
29
  newValue !== null &&
@@ -35,8 +36,12 @@ export const combineObjects = (arr) => {
35
36
  result[key] =
36
37
  existingValue !== null && existingValue !== undefined
37
38
  ? Array.isArray(existingValue)
38
- ? [...existingValue, newValue]
39
- : [existingValue, newValue]
39
+ ? Array.isArray(newValue)
40
+ ? [...existingValue, ...newValue]
41
+ : [...existingValue, newValue]
42
+ : Array.isArray(newValue)
43
+ ? [existingValue, ...newValue]
44
+ : [existingValue, newValue]
40
45
  : newValue;
41
46
  }
42
47
  }
@@ -81,7 +86,8 @@ export const isBoolean = (input) => typeof input === "boolean" ||
81
86
  input === true ||
82
87
  input === false;
83
88
  export const isPassword = (input) => input.length === 161;
84
- export const isDate = (input) => !isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0;
89
+ export const isDate = (input) => (isNumber(input) && new Date(input).getTime() > 0) ||
90
+ (!isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0);
85
91
  export const isValidID = (input) => {
86
92
  return typeof input === "string" && input.length === 32;
87
93
  };
@@ -198,7 +204,7 @@ export const objectToDotNotation = (input) => {
198
204
  // If the property is an array of strings or numbers, keep the array as is
199
205
  result[newKey] = value;
200
206
  }
201
- else if (typeof value === "object" && value !== null) {
207
+ else if (isObject(value)) {
202
208
  // If the property is an object, push it onto the stack for further processing
203
209
  stack.push({ obj: value, parentKey: newKey });
204
210
  }
@@ -231,4 +237,5 @@ export default class Utils {
231
237
  static isIP = isIP;
232
238
  static validateFieldType = validateFieldType;
233
239
  static objectToDotNotation = objectToDotNotation;
240
+ static isArrayOfNulls = isArrayOfNulls;
234
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.17",
3
+ "version": "1.0.0-rc.19",
4
4
  "description": "File-based Relational Database for large data",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist",
@@ -63,7 +63,7 @@
63
63
  },
64
64
  "scripts": {
65
65
  "build": "npx tsc",
66
- "test": "npx tsx watch ./index.test",
66
+ "test": "npx tsx watch ./text/index",
67
67
  "benchmark": "npx tsx watch ./benchmark.ts"
68
68
  }
69
69
  }