inibase 1.0.0-rc.125 → 1.0.0-rc.127
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 +18 -29
- package/dist/index.d.ts +16 -15
- package/dist/index.js +80 -54
- package/dist/utils.js +11 -10
- package/package.json +4 -2
package/dist/file.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { createWriteStream } from "node:fs";
|
|
2
1
|
import { access, appendFile, copyFile, constants as fsConstants, open, readFile, unlink, writeFile, } from "node:fs/promises";
|
|
3
2
|
import { join, resolve } from "node:path";
|
|
4
3
|
import { createInterface } from "node:readline";
|
|
5
4
|
import { Transform } from "node:stream";
|
|
6
5
|
import { pipeline } from "node:stream/promises";
|
|
7
6
|
import { createGunzip, createGzip } from "node:zlib";
|
|
8
|
-
import { spawn as spawnSync } from "node:child_process";
|
|
9
7
|
import Inison from "inison";
|
|
10
8
|
import { detectFieldType, isArrayOfObjects, isStringified, isNumber, isObject, } from "./utils.js";
|
|
11
9
|
import { compare, encodeID, exec, gunzip, gzip } from "./utils.server.js";
|
|
@@ -275,9 +273,9 @@ export async function get(filePath, lineNumbers, fieldType, fieldChildrenType, s
|
|
|
275
273
|
export const replace = async (filePath, replacements, totalItems) => {
|
|
276
274
|
const fileTempPath = filePath.replace(/([^/]+)\/?$/, ".tmp/$1");
|
|
277
275
|
const isReplacementsObject = isObject(replacements);
|
|
278
|
-
const
|
|
276
|
+
const isReplacementsLineNumbered = isReplacementsObject && !Number.isNaN(Number(Object.keys(replacements)[0]));
|
|
279
277
|
if (await isExists(filePath)) {
|
|
280
|
-
if (
|
|
278
|
+
if (isReplacementsLineNumbered) {
|
|
281
279
|
let fileHandle = null;
|
|
282
280
|
let fileTempHandle = null;
|
|
283
281
|
try {
|
|
@@ -328,34 +326,24 @@ export const replace = async (filePath, replacements, totalItems) => {
|
|
|
328
326
|
}
|
|
329
327
|
}
|
|
330
328
|
else {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (code === 0)
|
|
345
|
-
resolve([fileTempPath, filePath]);
|
|
346
|
-
else
|
|
347
|
-
resolve([fileTempPath, null]);
|
|
348
|
-
});
|
|
349
|
-
// Handle errors in spawning the sed process
|
|
350
|
-
sedProcess.on("error", () => {
|
|
351
|
-
resolve([fileTempPath, null]);
|
|
352
|
-
});
|
|
353
|
-
});
|
|
329
|
+
const escapedFilePath = escapeShellPath(filePath);
|
|
330
|
+
const escapedFileTempPath = escapeShellPath(fileTempPath);
|
|
331
|
+
const sedCommand = `sed -e s/.*/${replacements}/ -e /^$/s/^/${replacements}/ ${escapedFilePath}`;
|
|
332
|
+
const command = filePath.endsWith(".gz")
|
|
333
|
+
? `zcat ${escapedFilePath} | ${sedCommand} | gzip > ${escapedFileTempPath}`
|
|
334
|
+
: `${sedCommand} > ${escapedFileTempPath}`;
|
|
335
|
+
try {
|
|
336
|
+
await exec(command);
|
|
337
|
+
return [fileTempPath, filePath];
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
return [fileTempPath, null];
|
|
341
|
+
}
|
|
354
342
|
}
|
|
355
343
|
}
|
|
356
344
|
else if (isReplacementsObject) {
|
|
357
345
|
try {
|
|
358
|
-
if (
|
|
346
|
+
if (isReplacementsLineNumbered) {
|
|
359
347
|
const replacementsKeys = Object.keys(replacements)
|
|
360
348
|
.map(Number)
|
|
361
349
|
.toSorted((a, b) => a - b);
|
|
@@ -542,7 +530,8 @@ export const search = async (filePath, operator, comparedAtValue, logicalOperato
|
|
|
542
530
|
// Increment the line count for each line.
|
|
543
531
|
linesCount++;
|
|
544
532
|
// Search only in provided linesNumbers
|
|
545
|
-
if (searchIn?.size &&
|
|
533
|
+
if (searchIn?.size &&
|
|
534
|
+
(!searchIn.has(linesCount) || searchIn.has(-linesCount)))
|
|
546
535
|
continue;
|
|
547
536
|
// Decode the line for comparison.
|
|
548
537
|
const decodedLine = decode(line, fieldType, fieldChildrenType, secretKey);
|
package/dist/index.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export default class Inibase {
|
|
|
62
62
|
private totalItems;
|
|
63
63
|
constructor(database: string, mainFolder?: string);
|
|
64
64
|
private static errorMessages;
|
|
65
|
-
createError(
|
|
65
|
+
createError(name: ErrorCodes, variable?: string | number | (string | number)[], language?: ErrorLang): Error;
|
|
66
66
|
clear(): void;
|
|
67
67
|
private getFileExtension;
|
|
68
68
|
private _schemaToIdsPath;
|
|
@@ -132,36 +132,37 @@ export default class Inibase {
|
|
|
132
132
|
* @param {boolean} [onlyLinesNumbers]
|
|
133
133
|
* @return {*} {(Promise<Data | number | (Data | number)[] | null>)}
|
|
134
134
|
*/
|
|
135
|
-
get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers?: false): Promise<Data | null>;
|
|
136
|
-
get(tableName: string, where: string | number, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data | null>;
|
|
137
|
-
get(tableName: string, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data[] | null>;
|
|
138
|
-
get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: false | undefined, onlyLinesNumbers: true): Promise<number[] | null>;
|
|
139
|
-
get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers: true): Promise<number | null>;
|
|
135
|
+
get<TData extends Record<string, any> & Partial<Data>>(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers?: false): Promise<(Data & TData) | null>;
|
|
136
|
+
get<TData extends Record<string, any> & Partial<Data>>(tableName: string, where: string | number, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<(Data & TData) | null>;
|
|
137
|
+
get<TData extends Record<string, any> & Partial<Data>>(tableName: string, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<(Data & TData)[] | null>;
|
|
138
|
+
get<TData extends Record<string, any> & Partial<Data>>(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: false | undefined, onlyLinesNumbers: true): Promise<number[] | null>;
|
|
139
|
+
get<TData extends Record<string, any> & Partial<Data>>(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers: true): Promise<number | null>;
|
|
140
140
|
/**
|
|
141
141
|
* Create new item(s) in a table
|
|
142
142
|
*
|
|
143
143
|
* @param {string} tableName
|
|
144
|
-
* @param {(Data | Data[])} data Can be array of objects or a single object
|
|
144
|
+
* @param {((Data & TData) | (Data & TData)[])} data Can be array of objects or a single object
|
|
145
145
|
* @param {Options} [options] Pagination options, useful when the returnPostedData param is true
|
|
146
146
|
* @param {boolean} [returnPostedData] By default function returns void, if you want to get the posted data, set this param to true
|
|
147
147
|
* @return {*} {Promise<Data | Data[] | null | void>}
|
|
148
148
|
*/
|
|
149
|
-
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: boolean): Promise<void>;
|
|
150
|
-
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
151
|
-
post(tableName: string, data: Data[], options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
149
|
+
post<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: (Data & TData) | (Data & TData)[], options?: Options, returnPostedData?: boolean): Promise<void>;
|
|
150
|
+
post<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: Data & TData, options: Options | undefined, returnPostedData: true): Promise<(Data & TData) | null>;
|
|
151
|
+
post<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: (Data & TData)[], options: Options | undefined, returnPostedData: true): Promise<(Data & TData)[] | null>;
|
|
152
152
|
/**
|
|
153
153
|
* Update item(s) in a table
|
|
154
154
|
*
|
|
155
155
|
* @param {string} tableName
|
|
156
|
-
* @param {(Data | Data[])} data
|
|
156
|
+
* @param {(Data & TData) | (Data & TData[])} data
|
|
157
157
|
* @param {(number | string | (number | string)[] | Criteria)} [where]
|
|
158
158
|
* @param {Options} [options]
|
|
159
|
-
* @param {
|
|
159
|
+
* @param {boolean} [returnUpdatedData]
|
|
160
160
|
* @return {*} {Promise<Data | Data[] | null | undefined | void>}
|
|
161
161
|
*/
|
|
162
|
-
put(tableName: string, data: Data | Data[], where
|
|
163
|
-
put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data | null>;
|
|
164
|
-
put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true): Promise<Data[] | null>;
|
|
162
|
+
put<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: (Data & TData) | (Data & TData)[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: false): Promise<void>;
|
|
163
|
+
put<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: Data & TData, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true | boolean): Promise<(Data & TData) | null>;
|
|
164
|
+
put<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: (Data & TData)[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true | boolean): Promise<(Data & TData)[] | null>;
|
|
165
|
+
put<TData extends Record<string, any> & Partial<Data>>(tableName: string, data: (Data & TData) | (Data & TData)[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnUpdatedData: true | boolean): Promise<(Data & TData) | (Data & TData)[] | null>;
|
|
165
166
|
/**
|
|
166
167
|
* Delete item(s) in a table
|
|
167
168
|
*
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
-
import { randomBytes,
|
|
2
|
+
import { randomBytes, scryptSync } from "node:crypto";
|
|
3
3
|
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { glob, mkdir, readFile, readdir, rename, rm, unlink, writeFile, } from "node:fs/promises";
|
|
5
5
|
import { join, parse } from "node:path";
|
|
@@ -48,15 +48,17 @@ export default class Inibase {
|
|
|
48
48
|
: "please use dotenv",
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
|
-
createError(
|
|
52
|
-
const errorMessage = Inibase.errorMessages[language]?.[
|
|
51
|
+
createError(name, variable, language = "en") {
|
|
52
|
+
const errorMessage = Inibase.errorMessages[language]?.[name];
|
|
53
53
|
if (!errorMessage)
|
|
54
54
|
return new Error("ERR");
|
|
55
|
-
|
|
55
|
+
const error = new Error(variable
|
|
56
56
|
? Array.isArray(variable)
|
|
57
57
|
? errorMessage.replace(/\{variable\}/g, () => variable.shift()?.toString() ?? "")
|
|
58
58
|
: errorMessage.replaceAll("{variable}", `'${variable.toString()}'`)
|
|
59
59
|
: errorMessage.replaceAll("{variable}", ""));
|
|
60
|
+
error.name = name;
|
|
61
|
+
return error;
|
|
60
62
|
}
|
|
61
63
|
clear() {
|
|
62
64
|
this.tablesMap = new Map();
|
|
@@ -293,10 +295,12 @@ export default class Inibase {
|
|
|
293
295
|
throw this.createError("TABLE_EMPTY", tableName);
|
|
294
296
|
}
|
|
295
297
|
_validateData(data, schema, skipRequiredField = false) {
|
|
296
|
-
if (Utils.isArrayOfObjects(data))
|
|
298
|
+
if (Utils.isArrayOfObjects(data)) {
|
|
297
299
|
for (const single_data of data)
|
|
298
300
|
this._validateData(single_data, schema, skipRequiredField);
|
|
299
|
-
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (Utils.isObject(data)) {
|
|
300
304
|
for (const field of schema) {
|
|
301
305
|
if (!Object.hasOwn(data, field.key) ||
|
|
302
306
|
data[field.key] === null ||
|
|
@@ -304,7 +308,7 @@ export default class Inibase {
|
|
|
304
308
|
data[field.key] === "") {
|
|
305
309
|
if (field.required && !skipRequiredField)
|
|
306
310
|
throw this.createError("FIELD_REQUIRED", field.key);
|
|
307
|
-
|
|
311
|
+
continue;
|
|
308
312
|
}
|
|
309
313
|
if (!Utils.validateFieldType(data[field.key], field.type, (field.type === "array" || field.type === "object") &&
|
|
310
314
|
field.children &&
|
|
@@ -313,7 +317,12 @@ export default class Inibase {
|
|
|
313
317
|
: undefined))
|
|
314
318
|
throw this.createError("INVALID_TYPE", [
|
|
315
319
|
field.key,
|
|
316
|
-
Array.isArray(field.type) ? field.type.join(", ") : field.type
|
|
320
|
+
(Array.isArray(field.type) ? field.type.join(", ") : field.type) +
|
|
321
|
+
(Array.isArray(field.children)
|
|
322
|
+
? Utils.isArrayOfObjects(field.children)
|
|
323
|
+
? "[object]"
|
|
324
|
+
: `[${field.children.join("|")}]`
|
|
325
|
+
: `[${field.children}]`),
|
|
317
326
|
data[field.key],
|
|
318
327
|
]);
|
|
319
328
|
if ((field.type === "array" || field.type === "object") &&
|
|
@@ -329,7 +338,7 @@ export default class Inibase {
|
|
|
329
338
|
if (field.unique) {
|
|
330
339
|
let uniqueKey;
|
|
331
340
|
if (typeof field.unique === "boolean")
|
|
332
|
-
uniqueKey =
|
|
341
|
+
uniqueKey = field.id;
|
|
333
342
|
else
|
|
334
343
|
uniqueKey = field.unique;
|
|
335
344
|
if (!this.uniqueMap.has(uniqueKey))
|
|
@@ -381,7 +390,7 @@ export default class Inibase {
|
|
|
381
390
|
if (!Array.isArray(value))
|
|
382
391
|
value = [value];
|
|
383
392
|
if (Utils.isArrayOfObjects(fieldChildrenType))
|
|
384
|
-
return this.formatData(value, fieldChildrenType);
|
|
393
|
+
return this.formatData(value, fieldChildrenType, _formatOnlyAvailiableKeys);
|
|
385
394
|
if (!value.length)
|
|
386
395
|
return null;
|
|
387
396
|
return value.map((_value) => this.formatField(_value, fieldChildrenType));
|
|
@@ -433,22 +442,38 @@ export default class Inibase {
|
|
|
433
442
|
async checkUnique(tableName) {
|
|
434
443
|
const tablePath = join(this.databasePath, tableName);
|
|
435
444
|
const flattenSchema = Utils.flattenSchema(this.tablesMap.get(tableName).schema);
|
|
445
|
+
function hasDuplicates(setA, setB) {
|
|
446
|
+
for (const value of setA)
|
|
447
|
+
if (setB.has(value))
|
|
448
|
+
return true; // Stop and return true if a duplicate is found
|
|
449
|
+
return false; // No duplicates found
|
|
450
|
+
}
|
|
436
451
|
for await (const [_uniqueID, valueObject] of this.uniqueMap) {
|
|
437
452
|
let index = 0;
|
|
453
|
+
let shouldContinueParent = false; // Flag to manage parent loop continuation
|
|
454
|
+
const mergedLineNumbers = new Set();
|
|
438
455
|
for await (const [columnID, values] of valueObject.columnsValues) {
|
|
439
456
|
index++;
|
|
440
457
|
const field = flattenSchema.find(({ id }) => id === columnID);
|
|
441
|
-
const [searchResult, totalLines] = await File.search(join(tablePath, `${field.key}${this.getFileExtension(tableName)}`), "[]", Array.from(values), undefined, valueObject.exclude, field.type, field.children, 1, undefined, false, this.salt);
|
|
458
|
+
const [searchResult, totalLines, lineNumbers] = await File.search(join(tablePath, `${field.key}${this.getFileExtension(tableName)}`), "[]", Array.from(values), undefined, valueObject.exclude, field.type, field.children, 1, undefined, false, this.salt);
|
|
442
459
|
if (searchResult && totalLines > 0) {
|
|
443
|
-
if (
|
|
460
|
+
if (valueObject.columnsValues.size === 1 ||
|
|
461
|
+
hasDuplicates(lineNumbers, mergedLineNumbers)) {
|
|
462
|
+
this.uniqueMap = new Map();
|
|
444
463
|
throw this.createError("FIELD_UNIQUE", [
|
|
445
464
|
field.key,
|
|
446
465
|
Array.from(values).join(", "),
|
|
447
466
|
]);
|
|
467
|
+
}
|
|
468
|
+
lineNumbers.forEach(mergedLineNumbers.add, mergedLineNumbers);
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
shouldContinueParent = true; // Flag to skip the rest of this inner loop
|
|
472
|
+
break; // Exit the inner loop
|
|
448
473
|
}
|
|
449
|
-
else
|
|
450
|
-
return;
|
|
451
474
|
}
|
|
475
|
+
if (shouldContinueParent)
|
|
476
|
+
continue;
|
|
452
477
|
}
|
|
453
478
|
this.uniqueMap = new Map();
|
|
454
479
|
}
|
|
@@ -1118,9 +1143,8 @@ export default class Inibase {
|
|
|
1118
1143
|
.slice((options.page - 1) * options.perPage, options.page * options.perPage)
|
|
1119
1144
|
.map(Number), options, onlyOne);
|
|
1120
1145
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
if (RETURN && linesNumbers?.size) {
|
|
1146
|
+
const [LineNumberDataMap, linesNumbers] = await this.applyCriteria(tableName, schema, options, where);
|
|
1147
|
+
if (LineNumberDataMap && linesNumbers?.size) {
|
|
1124
1148
|
if (!this.totalItems.has(`${tableName}-*`))
|
|
1125
1149
|
this.totalItems.set(`${tableName}-*`, linesNumbers.size);
|
|
1126
1150
|
if (onlyLinesNumbers)
|
|
@@ -1130,8 +1154,8 @@ export default class Inibase {
|
|
|
1130
1154
|
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]), alreadyExistsColumnsIDs = Utils.flattenSchema(schema)
|
|
1131
1155
|
.filter(({ key }) => alreadyExistsColumns.includes(key))
|
|
1132
1156
|
.map(({ id }) => id);
|
|
1133
|
-
RETURN = Object.values(Utils.deepMerge(
|
|
1134
|
-
Utils.isFieldType("table", type, children)), Object.keys(
|
|
1157
|
+
RETURN = Object.values(Utils.deepMerge(LineNumberDataMap, await this.processSchemaData(tableName, Utils.filterSchema(schema, ({ id, type, children }) => !alreadyExistsColumnsIDs.includes(id) ||
|
|
1158
|
+
Utils.isFieldType("table", type, children)), Object.keys(LineNumberDataMap).map(Number), options)));
|
|
1135
1159
|
if (this.tablesMap.get(tableName).config.cache)
|
|
1136
1160
|
await writeFile(cachedFilePath, Array.from(linesNumbers).join(","));
|
|
1137
1161
|
}
|
|
@@ -1165,8 +1189,9 @@ export default class Inibase {
|
|
|
1165
1189
|
throw this.createError("NO_SCHEMA", tableName);
|
|
1166
1190
|
if (!returnPostedData)
|
|
1167
1191
|
returnPostedData = false;
|
|
1168
|
-
|
|
1169
|
-
|
|
1192
|
+
let clonedData = JSON.parse(JSON.stringify(data));
|
|
1193
|
+
const keys = UtilsServer.hashString(Object.keys(Array.isArray(clonedData) ? clonedData[0] : clonedData).join("."));
|
|
1194
|
+
await this.validateData(tableName, clonedData);
|
|
1170
1195
|
const renameList = [];
|
|
1171
1196
|
try {
|
|
1172
1197
|
await File.lock(join(tablePath, ".tmp"), keys);
|
|
@@ -1177,24 +1202,24 @@ export default class Inibase {
|
|
|
1177
1202
|
.name.split("-")
|
|
1178
1203
|
.map(Number);
|
|
1179
1204
|
this.totalItems.set(`${tableName}-*`, _totalItems);
|
|
1180
|
-
if (Utils.isArrayOfObjects(
|
|
1181
|
-
for (let index = 0; index <
|
|
1182
|
-
const element =
|
|
1205
|
+
if (Utils.isArrayOfObjects(clonedData))
|
|
1206
|
+
for (let index = 0; index < clonedData.length; index++) {
|
|
1207
|
+
const element = clonedData[index];
|
|
1183
1208
|
element.id = ++lastId;
|
|
1184
1209
|
element.createdAt = Date.now();
|
|
1185
1210
|
element.updatedAt = undefined;
|
|
1186
1211
|
}
|
|
1187
1212
|
else {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1213
|
+
clonedData.id = ++lastId;
|
|
1214
|
+
clonedData.createdAt = Date.now();
|
|
1215
|
+
clonedData.updatedAt = undefined;
|
|
1191
1216
|
}
|
|
1192
|
-
|
|
1217
|
+
clonedData = this.formatData(clonedData, this.tablesMap.get(tableName).schema, false);
|
|
1193
1218
|
const pathesContents = this.joinPathesContents(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1194
|
-
? Array.isArray(
|
|
1195
|
-
?
|
|
1196
|
-
:
|
|
1197
|
-
:
|
|
1219
|
+
? Array.isArray(clonedData)
|
|
1220
|
+
? clonedData.toReversed()
|
|
1221
|
+
: clonedData
|
|
1222
|
+
: clonedData);
|
|
1198
1223
|
await Promise.allSettled(Object.entries(pathesContents).map(async ([path, content]) => renameList.push(this.tablesMap.get(tableName).config.prepend
|
|
1199
1224
|
? await File.prepend(path, content)
|
|
1200
1225
|
: await File.append(path, content))));
|
|
@@ -1208,14 +1233,14 @@ export default class Inibase {
|
|
|
1208
1233
|
await rename(paginationFilePath, join(tablePath, `${lastId}-${this.totalItems.get(`${tableName}-*`)}.pagination`));
|
|
1209
1234
|
if (returnPostedData)
|
|
1210
1235
|
return this.get(tableName, this.tablesMap.get(tableName).config.prepend
|
|
1211
|
-
? Array.isArray(
|
|
1212
|
-
?
|
|
1236
|
+
? Array.isArray(clonedData)
|
|
1237
|
+
? clonedData.map((_, index) => index + 1).toReversed()
|
|
1213
1238
|
: 1
|
|
1214
|
-
: Array.isArray(
|
|
1215
|
-
?
|
|
1239
|
+
: Array.isArray(clonedData)
|
|
1240
|
+
? clonedData
|
|
1216
1241
|
.map((_, index) => this.totalItems.get(`${tableName}-*`) - index)
|
|
1217
1242
|
.toReversed()
|
|
1218
|
-
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(
|
|
1243
|
+
: this.totalItems.get(`${tableName}-*`), options, !Utils.isArrayOfObjects(clonedData));
|
|
1219
1244
|
}
|
|
1220
1245
|
finally {
|
|
1221
1246
|
if (renameList.length)
|
|
@@ -1230,21 +1255,22 @@ export default class Inibase {
|
|
|
1230
1255
|
const renameList = [];
|
|
1231
1256
|
const tablePath = join(this.databasePath, tableName);
|
|
1232
1257
|
await this.throwErrorIfTableEmpty(tableName);
|
|
1258
|
+
let clonedData = JSON.parse(JSON.stringify(data));
|
|
1233
1259
|
if (!where) {
|
|
1234
|
-
if (Utils.isArrayOfObjects(
|
|
1235
|
-
if (!
|
|
1260
|
+
if (Utils.isArrayOfObjects(clonedData)) {
|
|
1261
|
+
if (!clonedData.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
|
|
1236
1262
|
throw this.createError("INVALID_ID");
|
|
1237
|
-
return this.put(tableName,
|
|
1263
|
+
return this.put(tableName, clonedData, clonedData.map(({ id }) => id), options, returnUpdatedData);
|
|
1238
1264
|
}
|
|
1239
|
-
if (Object.hasOwn(
|
|
1240
|
-
if (!Utils.isValidID(
|
|
1241
|
-
throw this.createError("INVALID_ID",
|
|
1242
|
-
return this.put(tableName,
|
|
1265
|
+
if (Object.hasOwn(clonedData, "id")) {
|
|
1266
|
+
if (!Utils.isValidID(clonedData.id))
|
|
1267
|
+
throw this.createError("INVALID_ID", clonedData.id);
|
|
1268
|
+
return this.put(tableName, clonedData, clonedData.id, options, returnUpdatedData);
|
|
1243
1269
|
}
|
|
1244
|
-
await this.validateData(tableName,
|
|
1245
|
-
|
|
1270
|
+
await this.validateData(tableName, clonedData, true);
|
|
1271
|
+
clonedData = this.formatData(clonedData, this.tablesMap.get(tableName).schema, true);
|
|
1246
1272
|
const pathesContents = this.joinPathesContents(tableName, {
|
|
1247
|
-
...(({ id, ...restOfData }) => restOfData)(
|
|
1273
|
+
...(({ id, ...restOfData }) => restOfData)(clonedData),
|
|
1248
1274
|
updatedAt: Date.now(),
|
|
1249
1275
|
});
|
|
1250
1276
|
try {
|
|
@@ -1271,19 +1297,19 @@ export default class Inibase {
|
|
|
1271
1297
|
else if ((Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
1272
1298
|
Utils.isValidID(where)) {
|
|
1273
1299
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
1274
|
-
return this.put(tableName,
|
|
1300
|
+
return this.put(tableName, clonedData, lineNumbers, options, false);
|
|
1275
1301
|
}
|
|
1276
1302
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1277
1303
|
Utils.isNumber(where)) {
|
|
1278
1304
|
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1279
|
-
await this.validateData(tableName,
|
|
1280
|
-
|
|
1281
|
-
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Utils.isArrayOfObjects(
|
|
1282
|
-
?
|
|
1305
|
+
await this.validateData(tableName, clonedData, true);
|
|
1306
|
+
clonedData = this.formatData(clonedData, this.tablesMap.get(tableName).schema, true);
|
|
1307
|
+
const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Utils.isArrayOfObjects(clonedData)
|
|
1308
|
+
? clonedData.map((item) => ({
|
|
1283
1309
|
...item,
|
|
1284
1310
|
updatedAt: Date.now(),
|
|
1285
1311
|
}))
|
|
1286
|
-
: { ...
|
|
1312
|
+
: { ...clonedData, updatedAt: Date.now() })).map(([path, content]) => [
|
|
1287
1313
|
path,
|
|
1288
1314
|
[...(Array.isArray(where) ? where : [where])].reduce((obj, lineNum, index) => Object.assign(obj, {
|
|
1289
1315
|
[lineNum]: Array.isArray(content) ? content[index] : content,
|
|
@@ -1312,7 +1338,7 @@ export default class Inibase {
|
|
|
1312
1338
|
else if (Utils.isObject(where)) {
|
|
1313
1339
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
1314
1340
|
if (lineNumbers)
|
|
1315
|
-
return this.put(tableName,
|
|
1341
|
+
return this.put(tableName, clonedData, lineNumbers, options, returnUpdatedData);
|
|
1316
1342
|
}
|
|
1317
1343
|
else
|
|
1318
1344
|
throw this.createError("INVALID_PARAMETERS");
|
package/dist/utils.js
CHANGED
|
@@ -318,16 +318,17 @@ export const validateFieldType = (value, fieldType, fieldChildrenType) => {
|
|
|
318
318
|
fieldType = detectedFieldType;
|
|
319
319
|
}
|
|
320
320
|
if (fieldType === "array" && fieldChildrenType)
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
321
|
+
return (Array.isArray(value) &&
|
|
322
|
+
value.every((v) => {
|
|
323
|
+
let _fieldChildrenType = fieldChildrenType;
|
|
324
|
+
if (Array.isArray(_fieldChildrenType)) {
|
|
325
|
+
const detectedFieldType = detectFieldType(v, _fieldChildrenType);
|
|
326
|
+
if (!detectedFieldType)
|
|
327
|
+
return false;
|
|
328
|
+
_fieldChildrenType = detectedFieldType;
|
|
329
|
+
}
|
|
330
|
+
return validateFieldType(v, _fieldChildrenType);
|
|
331
|
+
}));
|
|
331
332
|
switch (fieldType) {
|
|
332
333
|
case "string":
|
|
333
334
|
return isString(value);
|
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.127",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Karim Amahtil",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
|
+
"@biomejs/biome": "1.9.4",
|
|
71
72
|
"@types/bun": "^1.1.10",
|
|
72
73
|
"@types/node": "^22.7.4",
|
|
73
74
|
"tinybench": "^3.0.7",
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
"scripts": {
|
|
82
83
|
"prepublish": "npx tsc",
|
|
83
84
|
"build": "npx tsc",
|
|
84
|
-
"benchmark": "./benchmark/run.js"
|
|
85
|
+
"benchmark": "./benchmark/run.js",
|
|
86
|
+
"test": "npx tsx ./tests/inibase.test.ts"
|
|
85
87
|
}
|
|
86
88
|
}
|