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 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 isReplacementsObjectHasLineNumbers = isReplacementsObject && !Number.isNaN(Number(Object.keys(replacements)[0]));
276
+ const isReplacementsLineNumbered = isReplacementsObject && !Number.isNaN(Number(Object.keys(replacements)[0]));
279
277
  if (await isExists(filePath)) {
280
- if (isReplacementsObjectHasLineNumbers) {
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
- return new Promise((resolve) => {
332
- const sedProcess = spawnSync("sed", [
333
- "-e",
334
- `s/.*/${replacements}/`,
335
- "-e",
336
- `/^$/s/^/${replacements}/`,
337
- filePath,
338
- ]);
339
- const outputStream = createWriteStream(fileTempPath); // Temp file for output
340
- // Pipe sed output to the temporary file
341
- sedProcess.stdout.pipe(outputStream);
342
- // Handle the process close
343
- sedProcess.on("close", (code) => {
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 (isReplacementsObjectHasLineNumbers) {
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 && (!searchIn.has(linesCount) || searchIn.has(-linesCount)))
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(code: ErrorCodes, variable?: string | number | (string | number)[], language?: ErrorLang): Error;
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 {false} [returnUpdatedData]
159
+ * @param {boolean} [returnUpdatedData]
160
160
  * @return {*} {Promise<Data | Data[] | null | undefined | void>}
161
161
  */
162
- put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnUpdatedData?: false): Promise<void>;
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, randomInt, scryptSync } from "node:crypto";
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(code, variable, language = "en") {
52
- const errorMessage = Inibase.errorMessages[language]?.[code];
51
+ createError(name, variable, language = "en") {
52
+ const errorMessage = Inibase.errorMessages[language]?.[name];
53
53
  if (!errorMessage)
54
54
  return new Error("ERR");
55
- return new Error(variable
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
- else if (Utils.isObject(data)) {
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
- return;
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 = randomInt(55);
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 (index === valueObject.columnsValues.size)
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
- let linesNumbers = null;
1122
- [RETURN, linesNumbers] = await this.applyCriteria(tableName, schema, options, where);
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(RETURN, await this.processSchemaData(tableName, Utils.filterSchema(schema, ({ id, type, children }) => !alreadyExistsColumnsIDs.includes(id) ||
1134
- Utils.isFieldType("table", type, children)), Object.keys(RETURN).map(Number), options)));
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
- const keys = UtilsServer.hashString(Object.keys(Array.isArray(data) ? data[0] : data).join("."));
1169
- await this.validateData(tableName, data);
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(data))
1181
- for (let index = 0; index < data.length; index++) {
1182
- const element = data[index];
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
- data.id = ++lastId;
1189
- data.createdAt = Date.now();
1190
- data.updatedAt = undefined;
1213
+ clonedData.id = ++lastId;
1214
+ clonedData.createdAt = Date.now();
1215
+ clonedData.updatedAt = undefined;
1191
1216
  }
1192
- data = this.formatData(data, this.tablesMap.get(tableName).schema, true);
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(data)
1195
- ? data.toReversed()
1196
- : data
1197
- : data);
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(data)
1212
- ? data.map((_, index) => index + 1).toReversed()
1236
+ ? Array.isArray(clonedData)
1237
+ ? clonedData.map((_, index) => index + 1).toReversed()
1213
1238
  : 1
1214
- : Array.isArray(data)
1215
- ? data
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(data));
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(data)) {
1235
- if (!data.every((item) => Object.hasOwn(item, "id") && Utils.isValidID(item.id)))
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, data, data.map(({ id }) => id), options, returnUpdatedData || undefined);
1263
+ return this.put(tableName, clonedData, clonedData.map(({ id }) => id), options, returnUpdatedData);
1238
1264
  }
1239
- if (Object.hasOwn(data, "id")) {
1240
- if (!Utils.isValidID(data.id))
1241
- throw this.createError("INVALID_ID", data.id);
1242
- return this.put(tableName, data, data.id, options, returnUpdatedData || undefined);
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, data, true);
1245
- data = this.formatData(data, this.tablesMap.get(tableName).schema, true);
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)(data),
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, data, lineNumbers, options, returnUpdatedData || undefined);
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, data, true);
1280
- data = this.formatData(data, this.tablesMap.get(tableName).schema, true);
1281
- const pathesContents = Object.fromEntries(Object.entries(this.joinPathesContents(tableName, Utils.isArrayOfObjects(data)
1282
- ? data.map((item) => ({
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
- : { ...data, updatedAt: Date.now() })).map(([path, content]) => [
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, data, lineNumbers, options, returnUpdatedData || undefined);
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 value.every((v) => {
322
- let _fieldChildrenType = fieldChildrenType;
323
- if (Array.isArray(_fieldChildrenType)) {
324
- const detectedFieldType = detectFieldType(v, _fieldChildrenType);
325
- if (!detectedFieldType)
326
- return false;
327
- _fieldChildrenType = detectedFieldType;
328
- }
329
- return validateFieldType(v, _fieldChildrenType);
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.125",
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
  }