inibase 1.0.0-rc.72 → 1.0.0-rc.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +3 -3
- package/dist/file.js +9 -11
- package/dist/index.d.ts +2 -5
- package/dist/index.js +74 -87
- package/dist/utils.d.ts +5 -2
- package/dist/utils.js +64 -12
- package/dist/utils.server.d.ts +3 -3
- package/dist/utils.server.js +25 -25
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "dotenv/config";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
3
5
|
import { createInterface } from "node:readline/promises";
|
|
4
6
|
import { parseArgs } from "node:util";
|
|
5
|
-
import { basename, join } from "node:path";
|
|
6
|
-
import { readFileSync } from "node:fs";
|
|
7
7
|
import Inison from "inison";
|
|
8
|
+
import { isExists } from "./file.js";
|
|
8
9
|
import Inibase from "./index.js";
|
|
9
10
|
import { isJSON, isNumber, setField, unsetField } from "./utils.js";
|
|
10
|
-
import { isExists } from "./file.js";
|
|
11
11
|
const textGreen = (input) => `\u001b[1;32m${input}\u001b[0m`;
|
|
12
12
|
const textRed = (input) => `\u001b[1;31m${input}\u001b[0m`;
|
|
13
13
|
const textBlue = (input) => `\u001b[1;34m${input}\u001b[0m`;
|
package/dist/file.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { access, appendFile, copyFile, constants as fsConstants, open, readFile, unlink, writeFile, } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
2
3
|
import { createInterface } from "node:readline";
|
|
3
4
|
import { Transform } from "node:stream";
|
|
4
5
|
import { pipeline } from "node:stream/promises";
|
|
5
|
-
import {
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { createGunzip, createGzip } from "node:zlib";
|
|
7
7
|
import Inison from "inison";
|
|
8
8
|
import { detectFieldType, isArrayOfObjects, isJSON, isNumber, isObject, } from "./utils.js";
|
|
9
|
-
import {
|
|
9
|
+
import { compare, encodeID, exec, gunzip, gzip } from "./utils.server.js";
|
|
10
10
|
export const lock = async (folderPath, prefix) => {
|
|
11
11
|
let lockFile = null;
|
|
12
12
|
const lockFilePath = join(folderPath, `${prefix ?? ""}.locked`);
|
|
@@ -109,7 +109,7 @@ export const encode = (input) => Array.isArray(input)
|
|
|
109
109
|
*/
|
|
110
110
|
const unSecureString = (input) => {
|
|
111
111
|
if (isNumber(input))
|
|
112
|
-
return Number(input);
|
|
112
|
+
return String(input).at(0) === "0" ? input : Number(input);
|
|
113
113
|
if (typeof input === "string")
|
|
114
114
|
return input.replace(/\\n/g, "\n") || null;
|
|
115
115
|
return null;
|
|
@@ -401,7 +401,6 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
401
401
|
const matchingLines = {};
|
|
402
402
|
// Initialize counters for line number, found items, and processed items.
|
|
403
403
|
let linesCount = 0;
|
|
404
|
-
let foundItems = 0;
|
|
405
404
|
const linesNumbers = new Set();
|
|
406
405
|
let fileHandle = null;
|
|
407
406
|
try {
|
|
@@ -426,13 +425,12 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
426
425
|
// If the line meets the conditions, process it.
|
|
427
426
|
if (meetsConditions) {
|
|
428
427
|
// Increment the found items counter.
|
|
429
|
-
foundItems++;
|
|
430
428
|
linesNumbers.add(linesCount);
|
|
431
429
|
// Check if the line should be skipped based on the offset.
|
|
432
|
-
if (offset &&
|
|
430
|
+
if (offset && linesNumbers.size < offset)
|
|
433
431
|
continue;
|
|
434
432
|
// Check if the limit has been reached.
|
|
435
|
-
if (limit &&
|
|
433
|
+
if (limit && linesNumbers.size > limit + (offset ?? 0)) {
|
|
436
434
|
if (readWholeFile)
|
|
437
435
|
continue;
|
|
438
436
|
break;
|
|
@@ -442,8 +440,8 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
442
440
|
}
|
|
443
441
|
}
|
|
444
442
|
// Convert the Map to an object using Object.fromEntries and return the result.
|
|
445
|
-
return
|
|
446
|
-
? [matchingLines,
|
|
443
|
+
return linesNumbers.size
|
|
444
|
+
? [matchingLines, linesNumbers.size, linesNumbers]
|
|
447
445
|
: [null, 0, null];
|
|
448
446
|
}
|
|
449
447
|
finally {
|
package/dist/index.d.ts
CHANGED
|
@@ -150,12 +150,9 @@ export default class Inibase {
|
|
|
150
150
|
*
|
|
151
151
|
* @param {string} tableName
|
|
152
152
|
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
153
|
-
* @return {
|
|
153
|
+
* @return {boolean | null} {(Promise<boolean | null>)}
|
|
154
154
|
*/
|
|
155
|
-
delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<
|
|
156
|
-
delete(tableName: string, where?: (number | string)[] | Criteria, _id?: string | string[]): Promise<string[] | null>;
|
|
157
|
-
delete(tableName: string, where?: number, _id?: string | string[]): Promise<number | null>;
|
|
158
|
-
delete(tableName: string, where?: number[], _id?: string | string[]): Promise<number[] | null>;
|
|
155
|
+
delete(tableName: string, where?: number | string | (number | string)[] | Criteria, _id?: string | string[]): Promise<boolean | null>;
|
|
159
156
|
/**
|
|
160
157
|
* Generate sum of column(s) in a table
|
|
161
158
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { randomBytes, scryptSync } from "node:crypto";
|
|
3
|
+
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { mkdir, readFile, readdir, rename, unlink, writeFile, } from "node:fs/promises";
|
|
4
5
|
import { join, parse } from "node:path";
|
|
5
|
-
import { scryptSync, randomBytes } from "node:crypto";
|
|
6
6
|
import { inspect } from "node:util";
|
|
7
7
|
import Inison from "inison";
|
|
8
8
|
import * as File from "./file.js";
|
|
@@ -97,7 +97,7 @@ export default class Inibase {
|
|
|
97
97
|
// if config not set => load default global env config
|
|
98
98
|
if (!config)
|
|
99
99
|
config = {
|
|
100
|
-
compression: process.env.INIBASE_COMPRESSION
|
|
100
|
+
compression: process.env.INIBASE_COMPRESSION == "true",
|
|
101
101
|
cache: process.env.INIBASE_CACHE === "true",
|
|
102
102
|
prepend: process.env.INIBASE_PREPEND === "true",
|
|
103
103
|
};
|
|
@@ -110,7 +110,7 @@ export default class Inibase {
|
|
|
110
110
|
await writeFile(join(tablePath, ".prepend.config"), "");
|
|
111
111
|
}
|
|
112
112
|
if (schema)
|
|
113
|
-
await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, 0, this.salt
|
|
113
|
+
await writeFile(join(tablePath, "schema.json"), JSON.stringify(UtilsServer.addIdToSchema(schema, 0, this.salt), null, 2));
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Update table schema or config
|
|
@@ -178,7 +178,7 @@ export default class Inibase {
|
|
|
178
178
|
// update columns files names based on field id
|
|
179
179
|
schema = UtilsServer.addIdToSchema(schema, table.schema?.length
|
|
180
180
|
? UtilsServer.findLastIdNumber(table.schema, this.salt)
|
|
181
|
-
: 0, this.salt
|
|
181
|
+
: 0, this.salt);
|
|
182
182
|
if (table.schema?.length) {
|
|
183
183
|
const replaceOldPathes = Utils.findChangedProperties(this._schemaToIdsPath(tableName, table.schema), this._schemaToIdsPath(tableName, schema));
|
|
184
184
|
if (replaceOldPathes)
|
|
@@ -189,7 +189,7 @@ export default class Inibase {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
else
|
|
192
|
-
schema = UtilsServer.addIdToSchema(schema, 0, this.salt
|
|
192
|
+
schema = UtilsServer.addIdToSchema(schema, 0, this.salt);
|
|
193
193
|
await writeFile(join(tablePath, "schema.json"), JSON.stringify(schema, null, 2));
|
|
194
194
|
}
|
|
195
195
|
delete this.tables[tableName];
|
|
@@ -277,22 +277,7 @@ export default class Inibase {
|
|
|
277
277
|
throw this.throwError("INVALID_TYPE", [
|
|
278
278
|
field.key,
|
|
279
279
|
Array.isArray(field.type) ? field.type.join(", ") : field.type,
|
|
280
|
-
|
|
281
|
-
"string",
|
|
282
|
-
"number",
|
|
283
|
-
"boolean",
|
|
284
|
-
"date",
|
|
285
|
-
"email",
|
|
286
|
-
"url",
|
|
287
|
-
"table",
|
|
288
|
-
"object",
|
|
289
|
-
"array",
|
|
290
|
-
"password",
|
|
291
|
-
"html",
|
|
292
|
-
"ip",
|
|
293
|
-
"json",
|
|
294
|
-
"id",
|
|
295
|
-
]) ?? "undefinedType",
|
|
280
|
+
data[field.key],
|
|
296
281
|
]);
|
|
297
282
|
if ((field.type === "array" || field.type === "object") &&
|
|
298
283
|
field.children &&
|
|
@@ -306,46 +291,26 @@ export default class Inibase {
|
|
|
306
291
|
}
|
|
307
292
|
}
|
|
308
293
|
}
|
|
309
|
-
formatField(value,
|
|
310
|
-
if (Array.isArray(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
294
|
+
formatField(value, fieldType, fieldChildrenType, _formatOnlyAvailiableKeys) {
|
|
295
|
+
if (Array.isArray(fieldType))
|
|
296
|
+
fieldType = (Utils.detectFieldType(value, fieldType) ??
|
|
297
|
+
fieldType[0]);
|
|
298
|
+
if (!value)
|
|
299
|
+
return null;
|
|
300
|
+
switch (fieldType) {
|
|
314
301
|
case "array":
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
? Utils.isNumber(item.id)
|
|
323
|
-
? Number(item.id)
|
|
324
|
-
: UtilsServer.decodeID(item.id, this.salt)
|
|
325
|
-
: null);
|
|
326
|
-
}
|
|
327
|
-
else if (value.every(Utils.isValidID) ||
|
|
328
|
-
value.every(Utils.isNumber))
|
|
329
|
-
return value.map((item) => Utils.isNumber(item)
|
|
330
|
-
? Number(item)
|
|
331
|
-
: UtilsServer.decodeID(item, this.salt));
|
|
332
|
-
}
|
|
333
|
-
else if (Utils.isValidID(value))
|
|
334
|
-
return [UtilsServer.decodeID(value, this.salt)];
|
|
335
|
-
else if (Utils.isNumber(value))
|
|
336
|
-
return [Number(value)];
|
|
337
|
-
}
|
|
338
|
-
else
|
|
339
|
-
return Array.isArray(value) ? value : [value];
|
|
340
|
-
}
|
|
341
|
-
else if (Utils.isArrayOfObjects(field.children))
|
|
342
|
-
return this.formatData(value, field.children, formatOnlyAvailiableKeys);
|
|
343
|
-
else if (Array.isArray(field.children))
|
|
344
|
-
return Array.isArray(value) ? value : [value];
|
|
345
|
-
break;
|
|
302
|
+
if (!fieldChildrenType)
|
|
303
|
+
return null;
|
|
304
|
+
if (!Array.isArray(value))
|
|
305
|
+
value = [value];
|
|
306
|
+
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
307
|
+
return this.formatData(value, fieldChildrenType, _formatOnlyAvailiableKeys);
|
|
308
|
+
return value.map((_value) => this.formatField(_value, fieldChildrenType));
|
|
346
309
|
case "object":
|
|
347
|
-
if (
|
|
348
|
-
|
|
310
|
+
if (Array.isArray(value))
|
|
311
|
+
value = value[0];
|
|
312
|
+
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
313
|
+
return this.formatData(value, fieldChildrenType, _formatOnlyAvailiableKeys);
|
|
349
314
|
break;
|
|
350
315
|
case "table":
|
|
351
316
|
if (Array.isArray(value))
|
|
@@ -373,6 +338,14 @@ export default class Inibase {
|
|
|
373
338
|
if (Array.isArray(value))
|
|
374
339
|
value = value[0];
|
|
375
340
|
return Utils.isNumber(value) ? Number(value) : null;
|
|
341
|
+
case "date": {
|
|
342
|
+
if (Array.isArray(value))
|
|
343
|
+
value = value[0];
|
|
344
|
+
if (Utils.isNumber(value))
|
|
345
|
+
return value;
|
|
346
|
+
const dateToTimestamp = Date.parse(value);
|
|
347
|
+
return Number.isNaN(dateToTimestamp) ? null : dateToTimestamp;
|
|
348
|
+
}
|
|
376
349
|
case "id":
|
|
377
350
|
if (Array.isArray(value))
|
|
378
351
|
value = value[0];
|
|
@@ -410,12 +383,12 @@ export default class Inibase {
|
|
|
410
383
|
const RETURN = {};
|
|
411
384
|
for (const field of schema) {
|
|
412
385
|
if (!Object.hasOwn(data, field.key)) {
|
|
413
|
-
if (formatOnlyAvailiableKeys
|
|
386
|
+
if (formatOnlyAvailiableKeys)
|
|
414
387
|
continue;
|
|
415
388
|
RETURN[field.key] = this.getDefaultValue(field);
|
|
416
389
|
continue;
|
|
417
390
|
}
|
|
418
|
-
RETURN[field.key] = this.formatField(data[field.key], field, formatOnlyAvailiableKeys);
|
|
391
|
+
RETURN[field.key] = this.formatField(data[field.key], field.type, field.children, formatOnlyAvailiableKeys);
|
|
419
392
|
}
|
|
420
393
|
return RETURN;
|
|
421
394
|
}
|
|
@@ -764,7 +737,7 @@ export default class Inibase {
|
|
|
764
737
|
searchOperator = "=";
|
|
765
738
|
searchComparedAtValue = value;
|
|
766
739
|
}
|
|
767
|
-
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, options.page - 1 * options.perPage + 1, true, this.salt);
|
|
740
|
+
const [searchResult, totalLines, linesNumbers] = await File.search(join(tablePath, `${key}${this.getFileExtension(tableName)}`), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.perPage, (options.page - 1) * options.perPage + 1, true, this.salt);
|
|
768
741
|
if (searchResult) {
|
|
769
742
|
RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
|
|
770
743
|
id,
|
|
@@ -813,7 +786,10 @@ export default class Inibase {
|
|
|
813
786
|
* @param {string} tableName
|
|
814
787
|
*/
|
|
815
788
|
async clearCache(tableName) {
|
|
816
|
-
|
|
789
|
+
const cacheFolderPath = join(this.databasePath, tableName, ".cache");
|
|
790
|
+
await Promise.all((await readdir(cacheFolderPath))
|
|
791
|
+
.filter((file) => file !== ".pagination")
|
|
792
|
+
.map((file) => unlink(join(cacheFolderPath, file))));
|
|
817
793
|
}
|
|
818
794
|
async get(tableName, where, options = {
|
|
819
795
|
page: 1,
|
|
@@ -834,8 +810,11 @@ export default class Inibase {
|
|
|
834
810
|
options.page = options.page || 1;
|
|
835
811
|
options.perPage = options.perPage || 15;
|
|
836
812
|
let RETURN;
|
|
837
|
-
let schema = (await this.
|
|
838
|
-
|
|
813
|
+
let schema = (await this.getTable(tableName)).schema;
|
|
814
|
+
if (!schema)
|
|
815
|
+
throw this.throwError("NO_SCHEMA", tableName);
|
|
816
|
+
if (!(await File.isExists(join(tablePath, `id${this.getFileExtension(tableName)}`))))
|
|
817
|
+
return null;
|
|
839
818
|
if (options.columns?.length)
|
|
840
819
|
schema = this._filterSchemaByColumns(schema, options.columns);
|
|
841
820
|
if (where &&
|
|
@@ -847,12 +826,12 @@ export default class Inibase {
|
|
|
847
826
|
RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
|
|
848
827
|
index +
|
|
849
828
|
1), options));
|
|
850
|
-
if (await File.isExists(join(tablePath, ".pagination")))
|
|
851
|
-
this.totalItems[`${tableName}-*`] = Number((await readFile(join(tablePath, ".pagination"), "utf8")).split(",")[1]);
|
|
829
|
+
if (await File.isExists(join(tablePath, ".cache", ".pagination")))
|
|
830
|
+
this.totalItems[`${tableName}-*`] = Number((await readFile(join(tablePath, ".cache", ".pagination"), "utf8")).split(",")[1]);
|
|
852
831
|
else {
|
|
853
832
|
const lastId = Number(Object.keys((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), -1, "number", undefined, this.salt, true))?.[0] ?? 0));
|
|
854
833
|
this.totalItems[`${tableName}-*`] = await File.count(join(tablePath, `id${this.getFileExtension(tableName)}`));
|
|
855
|
-
await writeFile(join(tablePath, ".pagination"), `${lastId},${this.totalItems[`${tableName}-*`]}`);
|
|
834
|
+
await writeFile(join(tablePath, ".cache", ".pagination"), `${lastId},${this.totalItems[`${tableName}-*`]}`);
|
|
856
835
|
}
|
|
857
836
|
}
|
|
858
837
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
@@ -908,8 +887,11 @@ export default class Inibase {
|
|
|
908
887
|
if (RETURN && linesNumbers) {
|
|
909
888
|
if (onlyLinesNumbers)
|
|
910
889
|
return Object.keys(RETURN).map(Number);
|
|
911
|
-
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0])
|
|
912
|
-
|
|
890
|
+
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]), alreadyExistsColumnsIDs = Utils.flattenSchema(schema)
|
|
891
|
+
.filter(({ key }) => alreadyExistsColumns.includes(key))
|
|
892
|
+
.map(({ id }) => id);
|
|
893
|
+
RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, Utils.filterSchema(schema, ({ id, type, children }) => !alreadyExistsColumnsIDs.includes(id) ||
|
|
894
|
+
Utils.isFieldType("table", type, children)), Object.keys(RETURN).map(Number), options)));
|
|
913
895
|
if (this.tables[tableName].config.cache)
|
|
914
896
|
await writeFile(cachedFilePath, Array.from(linesNumbers).join(","));
|
|
915
897
|
}
|
|
@@ -947,8 +929,8 @@ export default class Inibase {
|
|
|
947
929
|
try {
|
|
948
930
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
949
931
|
if (await File.isExists(join(tablePath, `id${this.getFileExtension(tableName)}`))) {
|
|
950
|
-
if (await File.isExists(join(tablePath, ".pagination")))
|
|
951
|
-
[lastId, this.totalItems[`${tableName}-*`]] = (await readFile(join(tablePath, ".pagination"), "utf8"))
|
|
932
|
+
if (await File.isExists(join(tablePath, ".cache", ".pagination")))
|
|
933
|
+
[lastId, this.totalItems[`${tableName}-*`]] = (await readFile(join(tablePath, ".cache", ".pagination"), "utf8"))
|
|
952
934
|
.split(",")
|
|
953
935
|
.map(Number);
|
|
954
936
|
else {
|
|
@@ -988,7 +970,7 @@ export default class Inibase {
|
|
|
988
970
|
this.totalItems[`${tableName}-*`] += Array.isArray(RETURN)
|
|
989
971
|
? RETURN.length
|
|
990
972
|
: 1;
|
|
991
|
-
await writeFile(join(tablePath, ".pagination"), `${lastId},${this.totalItems[`${tableName}-*`]}`);
|
|
973
|
+
await writeFile(join(tablePath, ".cache", ".pagination"), `${lastId},${this.totalItems[`${tableName}-*`]}`);
|
|
992
974
|
if (returnPostedData)
|
|
993
975
|
return this.get(tableName, this.tables[tableName].config.prepend
|
|
994
976
|
? Array.isArray(RETURN)
|
|
@@ -1028,8 +1010,8 @@ export default class Inibase {
|
|
|
1028
1010
|
return this.put(tableName, data, data.id);
|
|
1029
1011
|
}
|
|
1030
1012
|
let totalItems;
|
|
1031
|
-
if (await File.isExists(join(tablePath, ".pagination")))
|
|
1032
|
-
totalItems = (await readFile(join(tablePath, ".pagination"), "utf8"))
|
|
1013
|
+
if (await File.isExists(join(tablePath, ".cache", ".pagination")))
|
|
1014
|
+
totalItems = (await readFile(join(tablePath, ".cache", ".pagination"), "utf8"))
|
|
1033
1015
|
.split(",")
|
|
1034
1016
|
.map(Number)[1];
|
|
1035
1017
|
else
|
|
@@ -1078,7 +1060,7 @@ export default class Inibase {
|
|
|
1078
1060
|
}), {}),
|
|
1079
1061
|
]));
|
|
1080
1062
|
const keys = UtilsServer.hashString(Object.keys(pathesContents)
|
|
1081
|
-
.map((path) => path.replaceAll(
|
|
1063
|
+
.map((path) => path.replaceAll(this.getFileExtension(tableName), ""))
|
|
1082
1064
|
.join("."));
|
|
1083
1065
|
try {
|
|
1084
1066
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
@@ -1105,6 +1087,13 @@ export default class Inibase {
|
|
|
1105
1087
|
else
|
|
1106
1088
|
throw this.throwError("INVALID_PARAMETERS");
|
|
1107
1089
|
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Delete item(s) in a table
|
|
1092
|
+
*
|
|
1093
|
+
* @param {string} tableName
|
|
1094
|
+
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
1095
|
+
* @return {boolean | null} {(Promise<boolean | null>)}
|
|
1096
|
+
*/
|
|
1108
1097
|
async delete(tableName, where, _id) {
|
|
1109
1098
|
const renameList = [];
|
|
1110
1099
|
const tablePath = join(this.databasePath, tableName);
|
|
@@ -1113,15 +1102,15 @@ export default class Inibase {
|
|
|
1113
1102
|
try {
|
|
1114
1103
|
await File.lock(join(tablePath, ".tmp"));
|
|
1115
1104
|
await Promise.all((await readdir(tablePath))
|
|
1116
|
-
?.filter((fileName) => fileName.endsWith(
|
|
1105
|
+
?.filter((fileName) => fileName.endsWith(this.getFileExtension(tableName)))
|
|
1117
1106
|
.map(async (file) => unlink(join(tablePath, file))));
|
|
1118
1107
|
if (this.tables[tableName].config.cache)
|
|
1119
1108
|
await this.clearCache(tableName);
|
|
1109
|
+
return true;
|
|
1120
1110
|
}
|
|
1121
1111
|
finally {
|
|
1122
1112
|
await File.unlock(join(tablePath, ".tmp"));
|
|
1123
1113
|
}
|
|
1124
|
-
return "*";
|
|
1125
1114
|
}
|
|
1126
1115
|
if ((Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
1127
1116
|
Utils.isValidID(where)) {
|
|
@@ -1139,15 +1128,13 @@ export default class Inibase {
|
|
|
1139
1128
|
await Promise.all(renameList.map(async ([tempPath, filePath]) => rename(tempPath, filePath)));
|
|
1140
1129
|
if (this.tables[tableName].config.cache)
|
|
1141
1130
|
await this.clearCache(tableName);
|
|
1142
|
-
if (await File.isExists(join(tablePath, ".pagination"))) {
|
|
1143
|
-
const [lastId, totalItems] = (await readFile(join(tablePath, ".pagination"), "utf8"))
|
|
1131
|
+
if (await File.isExists(join(tablePath, ".cache", ".pagination"))) {
|
|
1132
|
+
const [lastId, totalItems] = (await readFile(join(tablePath, ".cache", ".pagination"), "utf8"))
|
|
1144
1133
|
.split(",")
|
|
1145
1134
|
.map(Number);
|
|
1146
|
-
await writeFile(join(tablePath, ".pagination"), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`);
|
|
1135
|
+
await writeFile(join(tablePath, ".cache", ".pagination"), `${lastId},${totalItems - (Array.isArray(where) ? where.length : 1)}`);
|
|
1147
1136
|
}
|
|
1148
|
-
|
|
1149
|
-
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1150
|
-
return where;
|
|
1137
|
+
return true;
|
|
1151
1138
|
}
|
|
1152
1139
|
finally {
|
|
1153
1140
|
if (renameList.length)
|
|
@@ -1162,7 +1149,7 @@ export default class Inibase {
|
|
|
1162
1149
|
}
|
|
1163
1150
|
else
|
|
1164
1151
|
throw this.throwError("INVALID_PARAMETERS");
|
|
1165
|
-
return
|
|
1152
|
+
return false;
|
|
1166
1153
|
}
|
|
1167
1154
|
async sum(tableName, columns, where) {
|
|
1168
1155
|
const RETURN = {};
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComparisonOperator, Field, FieldType, Schema } from "./index.js";
|
|
2
2
|
/**
|
|
3
3
|
* Type guard function to check if the input is an array of objects.
|
|
4
4
|
*
|
|
@@ -156,6 +156,9 @@ export declare const findChangedProperties: (obj1: Record<string, string>, obj2:
|
|
|
156
156
|
* @returns The detected field type as a string, or undefined if no matching type is found.
|
|
157
157
|
*/
|
|
158
158
|
export declare const detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
|
|
159
|
+
export declare const isFieldType: (compareAtType: string | string[], fieldType?: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | Schema) => boolean;
|
|
160
|
+
export declare const flattenSchema: (schema: Schema, keepParents?: boolean) => Schema;
|
|
161
|
+
export declare const filterSchema: (schema: Schema, callback: (arg0: Field) => boolean) => Field[];
|
|
159
162
|
/**
|
|
160
163
|
* Validates if the given value matches the specified field type(s).
|
|
161
164
|
*
|
|
@@ -165,7 +168,7 @@ export declare const detectFieldType: (input: any, availableTypes: FieldType[])
|
|
|
165
168
|
* @returns A boolean indicating whether the value matches the specified field type(s).
|
|
166
169
|
*/
|
|
167
170
|
export declare const validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
|
|
168
|
-
export declare function FormatObjectCriteriaValue(value: string
|
|
171
|
+
export declare function FormatObjectCriteriaValue(value: string): [
|
|
169
172
|
ComparisonOperator,
|
|
170
173
|
string | number | boolean | null | (string | number | null)[]
|
|
171
174
|
];
|
package/dist/utils.js
CHANGED
|
@@ -118,7 +118,7 @@ export const isHTML = (input) => /<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a
|
|
|
118
118
|
* Note: Validates the input against being a number, boolean, email, URL, or IP address to ensure it's a general string.
|
|
119
119
|
*/
|
|
120
120
|
export const isString = (input) => Object.prototype.toString.call(input) === "[object String]" &&
|
|
121
|
-
!isNumber(input);
|
|
121
|
+
(!isNumber(input) || String(input).at(0) === "0");
|
|
122
122
|
/**
|
|
123
123
|
* Checks if the input is a valid IP address format.
|
|
124
124
|
*
|
|
@@ -152,7 +152,9 @@ export const isPassword = (input) => typeof input === "string" && input.length =
|
|
|
152
152
|
* @param input - The input to be checked, can be of any type.
|
|
153
153
|
* @returns A boolean indicating whether the input is a valid date.
|
|
154
154
|
*/
|
|
155
|
-
export const isDate = (input) => !Number.isNaN(new Date(input).getTime()) ||
|
|
155
|
+
export const isDate = (input) => !Number.isNaN(new Date(input).getTime()) ||
|
|
156
|
+
!Number.isNaN(Date.parse(input)) ||
|
|
157
|
+
!!input.match(/\b\d{2}[/.-]\d{2}[/.-]\d{4}\b/);
|
|
156
158
|
/**
|
|
157
159
|
* Checks if the input is a valid ID.
|
|
158
160
|
*
|
|
@@ -206,6 +208,8 @@ export const detectFieldType = (input, availableTypes) => {
|
|
|
206
208
|
return "date";
|
|
207
209
|
if (availableTypes.includes("number"))
|
|
208
210
|
return "number";
|
|
211
|
+
if (availableTypes.includes("string") && String(input).at(0) === "0")
|
|
212
|
+
return "string";
|
|
209
213
|
}
|
|
210
214
|
else if (typeof input === "string") {
|
|
211
215
|
if (availableTypes.includes("table") && isValidID(input))
|
|
@@ -232,6 +236,59 @@ export const detectFieldType = (input, availableTypes) => {
|
|
|
232
236
|
return "array";
|
|
233
237
|
return undefined;
|
|
234
238
|
};
|
|
239
|
+
export const isFieldType = (compareAtType, fieldType, fieldChildrenType) => {
|
|
240
|
+
if (fieldType) {
|
|
241
|
+
if (Array.isArray(fieldType)) {
|
|
242
|
+
if (fieldType.some((type) => Array.isArray(compareAtType)
|
|
243
|
+
? compareAtType.includes(type)
|
|
244
|
+
: compareAtType === type))
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
else if ((Array.isArray(compareAtType) && compareAtType.includes(fieldType)) ||
|
|
248
|
+
compareAtType === fieldType)
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
if (fieldChildrenType) {
|
|
252
|
+
if (Array.isArray(fieldChildrenType)) {
|
|
253
|
+
if (!isArrayOfObjects(fieldChildrenType)) {
|
|
254
|
+
if (fieldChildrenType.some((type) => Array.isArray(compareAtType)
|
|
255
|
+
? compareAtType.includes(type)
|
|
256
|
+
: compareAtType === type))
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else if ((Array.isArray(compareAtType) &&
|
|
261
|
+
compareAtType.includes(fieldChildrenType)) ||
|
|
262
|
+
compareAtType === fieldChildrenType)
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
};
|
|
267
|
+
// Function to recursively flatten an array of objects and their nested children
|
|
268
|
+
export const flattenSchema = (schema, keepParents = false) => {
|
|
269
|
+
const result = [];
|
|
270
|
+
function _flattenHelper(item, parentKey) {
|
|
271
|
+
if (item.children && isArrayOfObjects(item.children)) {
|
|
272
|
+
if (keepParents)
|
|
273
|
+
result.push((({ children, ...rest }) => rest)(item));
|
|
274
|
+
for (const child of item.children)
|
|
275
|
+
_flattenHelper(child, item.key);
|
|
276
|
+
}
|
|
277
|
+
else
|
|
278
|
+
result.push({
|
|
279
|
+
...item,
|
|
280
|
+
key: parentKey ? `${parentKey}.${item.key}` : item.key,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
for (const item of schema)
|
|
284
|
+
_flattenHelper(item, "");
|
|
285
|
+
return result;
|
|
286
|
+
};
|
|
287
|
+
export const filterSchema = (schema, callback) => schema.filter((field) => {
|
|
288
|
+
if (field.children && isArrayOfObjects(field.children))
|
|
289
|
+
field.children = filterSchema(field.children, callback);
|
|
290
|
+
return callback(field);
|
|
291
|
+
});
|
|
235
292
|
/**
|
|
236
293
|
* Validates if the given value matches the specified field type(s).
|
|
237
294
|
*
|
|
@@ -303,7 +360,7 @@ export const validateFieldType = (value, fieldType, fieldChildrenType) => {
|
|
|
303
360
|
return false;
|
|
304
361
|
}
|
|
305
362
|
};
|
|
306
|
-
export function FormatObjectCriteriaValue(value
|
|
363
|
+
export function FormatObjectCriteriaValue(value) {
|
|
307
364
|
switch (value[0]) {
|
|
308
365
|
case ">":
|
|
309
366
|
case "<":
|
|
@@ -339,15 +396,10 @@ export function FormatObjectCriteriaValue(value, isParentArray = false) {
|
|
|
339
396
|
value.slice(1),
|
|
340
397
|
];
|
|
341
398
|
case "=":
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
]
|
|
347
|
-
: [
|
|
348
|
-
value.slice(0, 1),
|
|
349
|
-
`${value.slice(1)},`,
|
|
350
|
-
];
|
|
399
|
+
return [
|
|
400
|
+
value.slice(0, 1),
|
|
401
|
+
value.slice(1),
|
|
402
|
+
];
|
|
351
403
|
case "*":
|
|
352
404
|
return [
|
|
353
405
|
value.slice(0, 1),
|
package/dist/utils.server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
3
|
/// <reference types="node" resolution-mode="require"/>
|
|
4
|
-
import type { ComparisonOperator, FieldType, Schema } from "./index.js";
|
|
5
4
|
import { exec as execAsync, execFile as execFileAsync } from "node:child_process";
|
|
6
5
|
import { gunzip as gunzipAsync, gzip as gzipAsync } from "node:zlib";
|
|
6
|
+
import type { ComparisonOperator, Field, FieldType, Schema } from "./index.js";
|
|
7
7
|
export declare const exec: typeof execAsync.__promisify__;
|
|
8
8
|
export declare const execFile: typeof execFileAsync.__promisify__;
|
|
9
9
|
export declare const gzip: typeof gzipAsync.__promisify__;
|
|
@@ -39,7 +39,7 @@ export declare const encodeID: (id: number | string, secretKeyOrSalt: string | n
|
|
|
39
39
|
* @returns The decoded ID as a number.
|
|
40
40
|
*/
|
|
41
41
|
export declare const decodeID: (input: string, secretKeyOrSalt: string | number | Buffer) => number;
|
|
42
|
-
export declare const
|
|
42
|
+
export declare const extractIdsFromSchema: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => number[];
|
|
43
43
|
/**
|
|
44
44
|
* Finds the last ID number in a schema, potentially decoding it if encrypted.
|
|
45
45
|
*
|
|
@@ -57,7 +57,7 @@ export declare const findLastIdNumber: (schema: Schema, secretKeyOrSalt: string
|
|
|
57
57
|
* @param encodeIDs - If true, IDs will be encoded, else they will remain as numbers.
|
|
58
58
|
* @returns The updated schema with encoded IDs.
|
|
59
59
|
*/
|
|
60
|
-
export declare const addIdToSchema: (schema: Schema,
|
|
60
|
+
export declare const addIdToSchema: (schema: Schema, startWithID: number, secretKeyOrSalt: string | number | Buffer, encodeIDs?: boolean) => Field[];
|
|
61
61
|
export declare const encodeSchemaID: (schema: Schema, secretKeyOrSalt: string | number | Buffer) => Schema;
|
|
62
62
|
export declare const hashString: (str: string) => string;
|
|
63
63
|
/**
|
package/dist/utils.server.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { createCipheriv, createDecipheriv, randomBytes, scryptSync, createHash, } from "node:crypto";
|
|
2
|
-
import { detectFieldType, isArrayOfObjects, isNumber, isPassword, isValidID, } from "./utils.js";
|
|
3
|
-
import { promisify } from "node:util";
|
|
4
1
|
import { exec as execAsync, execFile as execFileAsync, } from "node:child_process";
|
|
2
|
+
import { createCipheriv, createDecipheriv, createHash, randomBytes, scryptSync, } from "node:crypto";
|
|
3
|
+
import { promisify } from "node:util";
|
|
5
4
|
import { gunzip as gunzipAsync, gzip as gzipAsync } from "node:zlib";
|
|
5
|
+
import { detectFieldType, isArrayOfObjects, isNumber, isPassword, isValidID, } from "./utils.js";
|
|
6
6
|
export const exec = promisify(execAsync);
|
|
7
7
|
export const execFile = promisify(execFileAsync);
|
|
8
8
|
export const gzip = promisify(gzipAsync);
|
|
@@ -69,7 +69,7 @@ export const decodeID = (input, secretKeyOrSalt) => {
|
|
|
69
69
|
return Number(decipher.update(input, "hex", "utf8") + decipher.final("utf8"));
|
|
70
70
|
};
|
|
71
71
|
// Function to recursively flatten an array of objects and their nested children
|
|
72
|
-
export const
|
|
72
|
+
export const extractIdsFromSchema = (schema, secretKeyOrSalt) => {
|
|
73
73
|
const result = [];
|
|
74
74
|
for (const field of schema) {
|
|
75
75
|
if (field.id)
|
|
@@ -77,7 +77,7 @@ export const flattenSchema = (schema, secretKeyOrSalt) => {
|
|
|
77
77
|
? field.id
|
|
78
78
|
: decodeID(field.id, secretKeyOrSalt));
|
|
79
79
|
if (field.children && isArrayOfObjects(field.children))
|
|
80
|
-
result.push(...
|
|
80
|
+
result.push(...extractIdsFromSchema(field.children, secretKeyOrSalt));
|
|
81
81
|
}
|
|
82
82
|
return result;
|
|
83
83
|
};
|
|
@@ -88,7 +88,7 @@ export const flattenSchema = (schema, secretKeyOrSalt) => {
|
|
|
88
88
|
* @param secretKeyOrSalt - The secret key or salt for decoding an encrypted ID, can be a string, number, or Buffer.
|
|
89
89
|
* @returns The last ID number in the schema, decoded if necessary.
|
|
90
90
|
*/
|
|
91
|
-
export const findLastIdNumber = (schema, secretKeyOrSalt) => Math.max(...
|
|
91
|
+
export const findLastIdNumber = (schema, secretKeyOrSalt) => Math.max(...extractIdsFromSchema(schema, secretKeyOrSalt));
|
|
92
92
|
/**
|
|
93
93
|
* Adds or updates IDs in a schema, encoding them using a provided secret key or salt.
|
|
94
94
|
*
|
|
@@ -98,30 +98,30 @@ export const findLastIdNumber = (schema, secretKeyOrSalt) => Math.max(...flatten
|
|
|
98
98
|
* @param encodeIDs - If true, IDs will be encoded, else they will remain as numbers.
|
|
99
99
|
* @returns The updated schema with encoded IDs.
|
|
100
100
|
*/
|
|
101
|
-
export const addIdToSchema = (schema,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
oldIndex = decodeID(field.id, secretKeyOrSalt);
|
|
109
|
-
if (!encodeIDs)
|
|
110
|
-
field.id = oldIndex;
|
|
101
|
+
export const addIdToSchema = (schema, startWithID, secretKeyOrSalt, encodeIDs) => {
|
|
102
|
+
function _addIdToField(field) {
|
|
103
|
+
if (!field.id) {
|
|
104
|
+
startWithID++;
|
|
105
|
+
field.id = encodeIDs
|
|
106
|
+
? encodeID(startWithID, secretKeyOrSalt)
|
|
107
|
+
: startWithID;
|
|
111
108
|
}
|
|
112
109
|
else {
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
if (isValidID(field.id)) {
|
|
111
|
+
if (!encodeIDs)
|
|
112
|
+
field.id = decodeID(field.id, secretKeyOrSalt);
|
|
113
|
+
}
|
|
114
|
+
else if (encodeIDs)
|
|
115
115
|
field.id = encodeID(field.id, secretKeyOrSalt);
|
|
116
116
|
}
|
|
117
|
+
if ((field.type === "array" || field.type === "object") &&
|
|
118
|
+
isArrayOfObjects(field.children))
|
|
119
|
+
field.children = _addIdToSchema(field.children);
|
|
120
|
+
return field;
|
|
117
121
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
oldIndex += field.children.length;
|
|
122
|
-
}
|
|
123
|
-
return field;
|
|
124
|
-
});
|
|
122
|
+
const _addIdToSchema = (schema) => schema.map(_addIdToField);
|
|
123
|
+
return _addIdToSchema(schema);
|
|
124
|
+
};
|
|
125
125
|
export const encodeSchemaID = (schema, secretKeyOrSalt) => schema.map((field) => ({
|
|
126
126
|
...field,
|
|
127
127
|
id: isNumber(field.id) ? encodeID(field.id, secretKeyOrSalt) : field.id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inibase",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.74",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Karim Amahtil",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"dotenv": "^16.4.5",
|
|
77
|
-
"inison": "
|
|
77
|
+
"inison": "1.0.0-rc.3"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"build": "npx tsc",
|