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 +35 -34
- package/dist/index.d.ts +11 -4
- package/dist/index.js +321 -319
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +13 -6
- package/package.json +2 -2
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) =>
|
|
54
|
+
const unSecureString = (input) => input
|
|
55
55
|
.replaceAll("<", "<")
|
|
56
56
|
.replaceAll(">", ">")
|
|
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
|
|
97
|
-
?
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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?:
|
|
6
|
-
updatedAt?:
|
|
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
|
|
79
|
-
|
|
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(
|
|
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).
|
|
509
|
-
|
|
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
|
-
|
|
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(
|
|
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 (
|
|
788
|
-
const lineNumbers = this.get(tableName, where, undefined, undefined, true);
|
|
789
|
-
if (!lineNumbers || !
|
|
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 (
|
|
834
|
-
const lineNumbers = this.get(tableName, where, undefined, undefined, true);
|
|
835
|
-
if (!lineNumbers || !
|
|
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 (
|
|
25
|
-
|
|
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
|
-
?
|
|
39
|
-
|
|
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) =>
|
|
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 (
|
|
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.
|
|
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
|
|
66
|
+
"test": "npx tsx watch ./text/index",
|
|
67
67
|
"benchmark": "npx tsx watch ./benchmark.ts"
|
|
68
68
|
}
|
|
69
69
|
}
|