inibase 1.0.0-rc.23 → 1.0.0-rc.25
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.d.ts +10 -10
- package/dist/file.js +193 -287
- package/dist/index.d.ts +6 -5
- package/dist/index.js +174 -133
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +3 -12
- package/dist/utils.server.d.ts +2 -2
- package/dist/utils.server.js +5 -5
- package/package.json +6 -3
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,7 @@ declare global {
|
|
|
59
59
|
export default class Inibase {
|
|
60
60
|
folder: string;
|
|
61
61
|
database: string;
|
|
62
|
-
table: string;
|
|
62
|
+
table: string | null;
|
|
63
63
|
pageInfo: pageInfo;
|
|
64
64
|
private cache;
|
|
65
65
|
private totalItems;
|
|
@@ -69,8 +69,9 @@ export default class Inibase {
|
|
|
69
69
|
setTableSchema(tableName: string, schema: Schema): Promise<void>;
|
|
70
70
|
getTableSchema(tableName: string): Promise<Schema | undefined>;
|
|
71
71
|
getField<Property extends keyof Field | "children">(keyPath: string, schema: Schema | Field, property?: Property): any;
|
|
72
|
-
validateData
|
|
73
|
-
|
|
72
|
+
private validateData;
|
|
73
|
+
private formatField;
|
|
74
|
+
private formatData;
|
|
74
75
|
private getDefaultValue;
|
|
75
76
|
private joinPathesContents;
|
|
76
77
|
private getItemsFromSchema;
|
|
@@ -78,10 +79,10 @@ export default class Inibase {
|
|
|
78
79
|
private applyCriteria;
|
|
79
80
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined): Promise<Data | null>;
|
|
80
81
|
get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true): Promise<number[] | null>;
|
|
81
|
-
post(tableName: string, data: Data | Data[], options
|
|
82
|
+
post(tableName: string, data: Data | Data[], options?: Options, returnPostedData?: false): Promise<void | null>;
|
|
82
83
|
post(tableName: string, data: Data, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
83
84
|
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
|
|
85
|
+
put(tableName: string, data: Data | Data[], where?: number | string | (number | string)[] | Criteria, options?: Options, returnPostedData?: false): Promise<void | null>;
|
|
85
86
|
put(tableName: string, data: Data, where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data | null>;
|
|
86
87
|
put(tableName: string, data: Data[], where: number | string | (number | string)[] | Criteria | undefined, options: Options | undefined, returnPostedData: true): Promise<Data[] | null>;
|
|
87
88
|
delete(tableName: string, where?: number | string, _id?: string | string[]): Promise<string | null>;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { unlink, rename, readFile, writeFile, mkdir, readdir, } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { existsSync, appendFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { scryptSync, randomBytes } from "node:crypto";
|
|
4
5
|
import File from "./file.js";
|
|
5
6
|
import Utils from "./utils.js";
|
|
6
7
|
import UtilsServer from "./utils.server.js";
|
|
@@ -19,7 +20,13 @@ export default class Inibase {
|
|
|
19
20
|
this.cache = new Map();
|
|
20
21
|
this.totalItems = {};
|
|
21
22
|
this.pageInfo = { page: 1, per_page: 15 };
|
|
22
|
-
|
|
23
|
+
if (!existsSync(".env") || !process.env.INIBASE_SECRET) {
|
|
24
|
+
this.salt = scryptSync(randomBytes(16), randomBytes(16), 32);
|
|
25
|
+
appendFileSync(".env", `INIBASE_SECRET=${this.salt.toString("hex")}\n`);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.salt = Buffer.from(process.env.INIBASE_SECRET, "hex");
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
throwError(code, variable, language = "en") {
|
|
25
32
|
const errorMessages = {
|
|
@@ -50,7 +57,7 @@ export default class Inibase {
|
|
|
50
57
|
const decodeIdFromSchema = (schema) => schema.map((field) => {
|
|
51
58
|
if (field.children && Utils.isArrayOfObjects(field.children))
|
|
52
59
|
field.children = decodeIdFromSchema(field.children);
|
|
53
|
-
if (!Utils.isNumber(field.id))
|
|
60
|
+
if (field.id && !Utils.isNumber(field.id))
|
|
54
61
|
field.id = UtilsServer.decodeID(field.id, this.salt);
|
|
55
62
|
return field;
|
|
56
63
|
});
|
|
@@ -72,7 +79,7 @@ export default class Inibase {
|
|
|
72
79
|
RETURN[UtilsServer.decodeID(field.id, this.salt)] =
|
|
73
80
|
(prefix ?? "") + field.key + ".inib";
|
|
74
81
|
return RETURN;
|
|
75
|
-
}, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath(await this.getTableSchema(tableName)), schemaToIdsPath(schema));
|
|
82
|
+
}, replaceOldPathes = Utils.findChangedProperties(schemaToIdsPath((await this.getTableSchema(tableName)) ?? []), schemaToIdsPath(schema));
|
|
76
83
|
if (replaceOldPathes)
|
|
77
84
|
for await (const [oldPath, newPath] of Object.entries(replaceOldPathes))
|
|
78
85
|
if (await File.isExists(join(TablePath, oldPath)))
|
|
@@ -88,7 +95,7 @@ export default class Inibase {
|
|
|
88
95
|
this.cache.set(TableSchemaPath, await readFile(TableSchemaPath, "utf8"));
|
|
89
96
|
if (!this.cache.get(TableSchemaPath))
|
|
90
97
|
return undefined;
|
|
91
|
-
const schema = JSON.parse(this.cache.get(TableSchemaPath)), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
|
|
98
|
+
const schema = JSON.parse(this.cache.get(TableSchemaPath) ?? ""), lastIdNumber = UtilsServer.findLastIdNumber(schema, this.salt);
|
|
92
99
|
return [
|
|
93
100
|
{
|
|
94
101
|
id: UtilsServer.encodeID(0, this.salt),
|
|
@@ -149,7 +156,7 @@ export default class Inibase {
|
|
|
149
156
|
throw this.throwError("FIELD_REQUIRED", key);
|
|
150
157
|
if (data.hasOwnProperty(key) &&
|
|
151
158
|
!Utils.validateFieldType(data[key], type, children && !Utils.isArrayOfObjects(children) ? children : undefined))
|
|
152
|
-
throw this.throwError("INVALID_TYPE", key);
|
|
159
|
+
throw this.throwError("INVALID_TYPE", key + " " + type + " " + data[key]);
|
|
153
160
|
if ((type === "array" || type === "object") &&
|
|
154
161
|
children &&
|
|
155
162
|
Utils.isArrayOfObjects(children))
|
|
@@ -157,85 +164,87 @@ export default class Inibase {
|
|
|
157
164
|
}
|
|
158
165
|
}
|
|
159
166
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
value.map((item) => Utils.isNumber(item.id)
|
|
167
|
+
formatField(value, field, formatOnlyAvailiableKeys) {
|
|
168
|
+
if (Array.isArray(field.type))
|
|
169
|
+
field.type = Utils.detectFieldType(value, field.type) ?? field.type[0];
|
|
170
|
+
switch (field.type) {
|
|
171
|
+
case "array":
|
|
172
|
+
if (!Array.isArray(value))
|
|
173
|
+
value = [value];
|
|
174
|
+
if (typeof field.children === "string") {
|
|
175
|
+
if (field.type === "array" && field.children === "table") {
|
|
176
|
+
if (Array.isArray(value)) {
|
|
177
|
+
if (Utils.isArrayOfObjects(value)) {
|
|
178
|
+
if (value.every((item) => item.hasOwnProperty("id") &&
|
|
179
|
+
(Utils.isValidID(item.id) || Utils.isNumber(item.id))))
|
|
180
|
+
value.map((item) => item.id
|
|
181
|
+
? Utils.isNumber(item.id)
|
|
176
182
|
? Number(item.id)
|
|
177
|
-
: UtilsServer.decodeID(item.id, this.salt)
|
|
178
|
-
|
|
179
|
-
else if (value.every(Utils.isValidID) ||
|
|
180
|
-
value.every(Utils.isNumber))
|
|
181
|
-
return value.map((item) => Utils.isNumber(item)
|
|
182
|
-
? Number(item)
|
|
183
|
-
: UtilsServer.decodeID(item, this.salt));
|
|
183
|
+
: UtilsServer.decodeID(item.id, this.salt)
|
|
184
|
+
: null);
|
|
184
185
|
}
|
|
185
|
-
else if (Utils.isValidID
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
else if (value.every(Utils.isValidID) ||
|
|
187
|
+
value.every(Utils.isNumber))
|
|
188
|
+
return value.map((item) => Utils.isNumber(item)
|
|
189
|
+
? Number(item)
|
|
190
|
+
: UtilsServer.decodeID(item, this.salt));
|
|
189
191
|
}
|
|
190
|
-
else if (
|
|
191
|
-
return value;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return this.formatData(value, field.children, formatOnlyAvailiableKeys);
|
|
195
|
-
else if (Array.isArray(field.children))
|
|
196
|
-
return Array.isArray(value) ? value : [value];
|
|
197
|
-
break;
|
|
198
|
-
case "object":
|
|
199
|
-
if (Utils.isArrayOfObjects(field.children))
|
|
200
|
-
return this.formatData(value, field.children, formatOnlyAvailiableKeys);
|
|
201
|
-
break;
|
|
202
|
-
case "table":
|
|
203
|
-
if (Array.isArray(value))
|
|
204
|
-
value = value[0];
|
|
205
|
-
if (Utils.isObject(value)) {
|
|
206
|
-
if (value.hasOwnProperty("id") &&
|
|
207
|
-
(Utils.isValidID(value.id) ||
|
|
208
|
-
Utils.isNumber(value.id)))
|
|
209
|
-
return Utils.isNumber(value.id)
|
|
210
|
-
? Number(value.id)
|
|
211
|
-
: UtilsServer.decodeID(value.id, this.salt);
|
|
192
|
+
else if (Utils.isValidID(value))
|
|
193
|
+
return [UtilsServer.decodeID(value, this.salt)];
|
|
194
|
+
else if (Utils.isNumber(value))
|
|
195
|
+
return [Number(value)];
|
|
212
196
|
}
|
|
213
|
-
else if (
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
if (
|
|
230
|
-
value
|
|
197
|
+
else if (value.hasOwnProperty(field.key))
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
else if (Utils.isArrayOfObjects(field.children))
|
|
201
|
+
return this.formatData(value, field.children, formatOnlyAvailiableKeys);
|
|
202
|
+
else if (Array.isArray(field.children))
|
|
203
|
+
return Array.isArray(value) ? value : [value];
|
|
204
|
+
break;
|
|
205
|
+
case "object":
|
|
206
|
+
if (Utils.isArrayOfObjects(field.children))
|
|
207
|
+
return this.formatData(value, field.children, formatOnlyAvailiableKeys);
|
|
208
|
+
break;
|
|
209
|
+
case "table":
|
|
210
|
+
if (Array.isArray(value))
|
|
211
|
+
value = value[0];
|
|
212
|
+
if (Utils.isObject(value)) {
|
|
213
|
+
if (value.hasOwnProperty("id") &&
|
|
214
|
+
(Utils.isValidID(value.id) ||
|
|
215
|
+
Utils.isNumber(value.id)))
|
|
216
|
+
return Utils.isNumber(value.id)
|
|
217
|
+
? Number(value.id)
|
|
218
|
+
: UtilsServer.decodeID(value.id, this.salt);
|
|
219
|
+
}
|
|
220
|
+
else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
231
221
|
return Utils.isNumber(value)
|
|
232
|
-
? value
|
|
222
|
+
? Number(value)
|
|
233
223
|
: UtilsServer.decodeID(value, this.salt);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
224
|
+
break;
|
|
225
|
+
case "password":
|
|
226
|
+
if (Array.isArray(value))
|
|
227
|
+
value = value[0];
|
|
228
|
+
return typeof value === "string" && value.length === 161
|
|
229
|
+
? value
|
|
230
|
+
: UtilsServer.hashPassword(String(value));
|
|
231
|
+
case "number":
|
|
232
|
+
if (Array.isArray(value))
|
|
233
|
+
value = value[0];
|
|
234
|
+
return Utils.isNumber(value) ? Number(value) : null;
|
|
235
|
+
case "id":
|
|
236
|
+
if (Array.isArray(value))
|
|
237
|
+
value = value[0];
|
|
238
|
+
return Utils.isNumber(value)
|
|
239
|
+
? value
|
|
240
|
+
: UtilsServer.decodeID(value, this.salt);
|
|
241
|
+
default:
|
|
242
|
+
return value;
|
|
243
|
+
}
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
formatData(data, schema, formatOnlyAvailiableKeys) {
|
|
247
|
+
this.validateData(data, schema, formatOnlyAvailiableKeys);
|
|
239
248
|
if (Utils.isArrayOfObjects(data))
|
|
240
249
|
return data.map((single_data) => this.formatData(single_data, schema, formatOnlyAvailiableKeys));
|
|
241
250
|
else if (Utils.isObject(data)) {
|
|
@@ -247,7 +256,7 @@ export default class Inibase {
|
|
|
247
256
|
RETURN[field.key] = this.getDefaultValue(field);
|
|
248
257
|
continue;
|
|
249
258
|
}
|
|
250
|
-
RETURN[field.key] = formatField(data[field.key], field);
|
|
259
|
+
RETURN[field.key] = this.formatField(data[field.key], field, formatOnlyAvailiableKeys);
|
|
251
260
|
}
|
|
252
261
|
return RETURN;
|
|
253
262
|
}
|
|
@@ -382,22 +391,24 @@ export default class Inibase {
|
|
|
382
391
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
383
392
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field.children, this.salt);
|
|
384
393
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
RETURN[index]
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
394
|
+
if (items)
|
|
395
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
396
|
+
if (!RETURN[index])
|
|
397
|
+
RETURN[index] = {};
|
|
398
|
+
RETURN[index][field.key] = item
|
|
399
|
+
? await this.get(field.key, item, options)
|
|
400
|
+
: this.getDefaultValue(field);
|
|
401
|
+
}
|
|
392
402
|
}
|
|
393
403
|
else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
|
|
394
404
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
395
405
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
RETURN[index]
|
|
399
|
-
|
|
400
|
-
|
|
406
|
+
if (items)
|
|
407
|
+
for (const [index, item] of Object.entries(items)) {
|
|
408
|
+
if (!RETURN[index])
|
|
409
|
+
RETURN[index] = {};
|
|
410
|
+
RETURN[index][field.key] = item ?? this.getDefaultValue(field);
|
|
411
|
+
}
|
|
401
412
|
}
|
|
402
413
|
}
|
|
403
414
|
else if (field.type === "object") {
|
|
@@ -424,23 +435,30 @@ export default class Inibase {
|
|
|
424
435
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
425
436
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, "number", undefined, this.salt);
|
|
426
437
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
RETURN[index]
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
438
|
+
if (items)
|
|
439
|
+
for await (const [index, item] of Object.entries(items)) {
|
|
440
|
+
if (!RETURN[index])
|
|
441
|
+
RETURN[index] = {};
|
|
442
|
+
RETURN[index][field.key] = item
|
|
443
|
+
? await this.get(field.key, item, options)
|
|
444
|
+
: this.getDefaultValue(field);
|
|
445
|
+
}
|
|
434
446
|
}
|
|
435
447
|
}
|
|
436
448
|
else if (await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))) {
|
|
437
449
|
const [items, total_lines] = await File.get(join(path, (prefix ?? "") + field.key + ".inib"), linesNumber, field.type, field?.children, this.salt);
|
|
438
450
|
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
RETURN[index]
|
|
442
|
-
|
|
443
|
-
|
|
451
|
+
if (items)
|
|
452
|
+
for (const [index, item] of Object.entries(items)) {
|
|
453
|
+
if (!RETURN[index])
|
|
454
|
+
RETURN[index] = {};
|
|
455
|
+
RETURN[index][field.key] = item ?? this.getDefaultValue(field);
|
|
456
|
+
}
|
|
457
|
+
else
|
|
458
|
+
RETURN = Object.fromEntries(Object.entries(RETURN).map(([index, data]) => [
|
|
459
|
+
index,
|
|
460
|
+
{ ...data, [field.key]: this.getDefaultValue(field) },
|
|
461
|
+
]));
|
|
444
462
|
}
|
|
445
463
|
}
|
|
446
464
|
return RETURN;
|
|
@@ -528,8 +546,8 @@ export default class Inibase {
|
|
|
528
546
|
let searchOperator = undefined, searchComparedAtValue = undefined, searchLogicalOperator = undefined;
|
|
529
547
|
if (Utils.isObject(value)) {
|
|
530
548
|
if (value?.or &&
|
|
531
|
-
Array.isArray(value
|
|
532
|
-
const searchCriteria = value
|
|
549
|
+
Array.isArray(value?.or)) {
|
|
550
|
+
const searchCriteria = (value?.or)
|
|
533
551
|
.map((single_or) => typeof single_or === "string"
|
|
534
552
|
? this.FormatObjectCriteriaValue(single_or)
|
|
535
553
|
: ["=", single_or])
|
|
@@ -539,11 +557,11 @@ export default class Inibase {
|
|
|
539
557
|
searchComparedAtValue = searchCriteria.map((single_or) => single_or[1]);
|
|
540
558
|
searchLogicalOperator = "or";
|
|
541
559
|
}
|
|
542
|
-
delete value
|
|
560
|
+
delete value?.or;
|
|
543
561
|
}
|
|
544
562
|
if (value?.and &&
|
|
545
|
-
Array.isArray(value
|
|
546
|
-
const searchCriteria = value
|
|
563
|
+
Array.isArray(value?.and)) {
|
|
564
|
+
const searchCriteria = (value?.and)
|
|
547
565
|
.map((single_and) => typeof single_and === "string"
|
|
548
566
|
? this.FormatObjectCriteriaValue(single_and)
|
|
549
567
|
: ["=", single_and])
|
|
@@ -553,7 +571,7 @@ export default class Inibase {
|
|
|
553
571
|
searchComparedAtValue = searchCriteria.map((single_and) => single_and[1]);
|
|
554
572
|
searchLogicalOperator = "and";
|
|
555
573
|
}
|
|
556
|
-
delete value
|
|
574
|
+
delete value?.and;
|
|
557
575
|
}
|
|
558
576
|
}
|
|
559
577
|
else if (Array.isArray(value)) {
|
|
@@ -579,9 +597,14 @@ export default class Inibase {
|
|
|
579
597
|
searchOperator = "=";
|
|
580
598
|
searchComparedAtValue = value;
|
|
581
599
|
}
|
|
582
|
-
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);
|
|
600
|
+
const [searchResult, total_lines] = await File.search(join(this.folder, this.database, tableName, key + ".inib"), searchOperator ?? "=", searchComparedAtValue ?? null, searchLogicalOperator, field?.type, field?.children, options.per_page, options.page - 1 * options.per_page + 1, true, this.salt);
|
|
583
601
|
if (searchResult) {
|
|
584
|
-
RETURN = Utils.deepMerge(RETURN, searchResult)
|
|
602
|
+
RETURN = Utils.deepMerge(RETURN, Object.fromEntries(Object.entries(searchResult).map(([id, value]) => [
|
|
603
|
+
id,
|
|
604
|
+
{
|
|
605
|
+
[key]: value,
|
|
606
|
+
},
|
|
607
|
+
])));
|
|
585
608
|
this.totalItems[tableName + "-" + key] = total_lines;
|
|
586
609
|
}
|
|
587
610
|
if (allTrue && index > 0) {
|
|
@@ -599,12 +622,13 @@ export default class Inibase {
|
|
|
599
622
|
page: 1,
|
|
600
623
|
per_page: 15,
|
|
601
624
|
}, onlyOne, onlyLinesNumbers) {
|
|
602
|
-
if (
|
|
603
|
-
options.columns
|
|
604
|
-
|
|
605
|
-
options.columns
|
|
606
|
-
|
|
607
|
-
|
|
625
|
+
if (options.columns) {
|
|
626
|
+
if (!Array.isArray(options.columns))
|
|
627
|
+
options.columns = [options.columns];
|
|
628
|
+
if (options.columns.length &&
|
|
629
|
+
!options.columns.includes("id"))
|
|
630
|
+
options.columns.push("id");
|
|
631
|
+
}
|
|
608
632
|
if (!options.page)
|
|
609
633
|
options.page = 1;
|
|
610
634
|
if (!options.per_page)
|
|
@@ -635,7 +659,7 @@ export default class Inibase {
|
|
|
635
659
|
return null;
|
|
636
660
|
})
|
|
637
661
|
.filter((i) => i);
|
|
638
|
-
if (options.columns.length)
|
|
662
|
+
if (options.columns && options.columns.length)
|
|
639
663
|
schema = filterSchemaByColumns(schema, options.columns);
|
|
640
664
|
if (!where) {
|
|
641
665
|
// Display all data
|
|
@@ -658,7 +682,7 @@ export default class Inibase {
|
|
|
658
682
|
? Object.keys(lineNumbers).map(Number)
|
|
659
683
|
: null;
|
|
660
684
|
RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
|
|
661
|
-
if (RETURN.length && !Array.isArray(where))
|
|
685
|
+
if (RETURN && RETURN.length && !Array.isArray(where))
|
|
662
686
|
RETURN = RETURN[0];
|
|
663
687
|
}
|
|
664
688
|
else if (Utils.isObject(where)) {
|
|
@@ -667,7 +691,7 @@ export default class Inibase {
|
|
|
667
691
|
if (RETURN) {
|
|
668
692
|
if (onlyLinesNumbers)
|
|
669
693
|
return Object.keys(RETURN).map(Number);
|
|
670
|
-
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0])
|
|
694
|
+
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]);
|
|
671
695
|
RETURN = Object.values(Utils.deepMerge(RETURN, await this.getItemsFromSchema(tableName, schema.filter((field) => !alreadyExistsColumns.includes(field.key)), Object.keys(RETURN).map(Number), options)));
|
|
672
696
|
}
|
|
673
697
|
}
|
|
@@ -700,7 +724,7 @@ export default class Inibase {
|
|
|
700
724
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
701
725
|
let [last_line_number, last_id] = (await File.isExists(idFilePath))
|
|
702
726
|
? Object.entries((await File.get(idFilePath, -1, "number", undefined, this.salt))[0] ??
|
|
703
|
-
{})[0]
|
|
727
|
+
{})[0].map(Number) ?? [0, 0]
|
|
704
728
|
: [0, 0];
|
|
705
729
|
if (Utils.isArrayOfObjects(data))
|
|
706
730
|
RETURN = data.map(({ id, updatedAt, createdAt, ...rest }) => ({
|
|
@@ -720,10 +744,17 @@ export default class Inibase {
|
|
|
720
744
|
const pathesContents = this.joinPathesContents(join(this.folder, this.database, tableName), RETURN);
|
|
721
745
|
last_line_number += 1;
|
|
722
746
|
for await (const [path, content] of Object.entries(pathesContents))
|
|
723
|
-
await File.append(path,
|
|
747
|
+
await File.append(path,
|
|
748
|
+
// Array.isArray(content)
|
|
749
|
+
// ? content.reduce((obj, value, index) => {
|
|
750
|
+
// obj[last_line_number + index] = value;
|
|
751
|
+
// return obj;
|
|
752
|
+
// }, {})
|
|
753
|
+
// : { [last_line_number]: content }
|
|
754
|
+
content, last_line_number);
|
|
724
755
|
if (returnPostedData)
|
|
725
756
|
return this.get(tableName, Utils.isArrayOfObjects(RETURN)
|
|
726
|
-
? RETURN.map((data) => data.id)
|
|
757
|
+
? RETURN.map((data) => Number(data.id))
|
|
727
758
|
: RETURN.id, options, !Utils.isArrayOfObjects(data) // return only one item if data is not array of objects
|
|
728
759
|
);
|
|
729
760
|
}
|
|
@@ -742,7 +773,9 @@ export default class Inibase {
|
|
|
742
773
|
if (Utils.isArrayOfObjects(data)) {
|
|
743
774
|
if (!data.every((item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)))
|
|
744
775
|
throw this.throwError("INVALID_ID");
|
|
745
|
-
return this.put(tableName, data, data
|
|
776
|
+
return this.put(tableName, data, data
|
|
777
|
+
.filter((item) => item.id !== undefined)
|
|
778
|
+
.map((item) => item.id));
|
|
746
779
|
}
|
|
747
780
|
else if (data.hasOwnProperty("id")) {
|
|
748
781
|
if (!Utils.isValidID(data.id))
|
|
@@ -825,6 +858,8 @@ export default class Inibase {
|
|
|
825
858
|
if ((Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
826
859
|
Utils.isValidID(where)) {
|
|
827
860
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
861
|
+
if (!lineNumbers)
|
|
862
|
+
return null;
|
|
828
863
|
return this.delete(tableName, lineNumbers, where);
|
|
829
864
|
}
|
|
830
865
|
else if ((Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
@@ -833,7 +868,7 @@ export default class Inibase {
|
|
|
833
868
|
const files = (await readdir(join(this.folder, this.database, tableName)))?.filter((fileName) => fileName.endsWith(".inib"));
|
|
834
869
|
if (files.length) {
|
|
835
870
|
if (!_id)
|
|
836
|
-
_id = Object.
|
|
871
|
+
_id = Object.entries((await File.get(join(this.folder, this.database, tableName, "id.inib"), where, "number", undefined, this.salt))[0] ?? {}).map(([_key, id]) => UtilsServer.encodeID(Number(id), this.salt));
|
|
837
872
|
if (!_id.length)
|
|
838
873
|
throw this.throwError("NO_ITEMS", tableName);
|
|
839
874
|
for await (const file of files)
|
|
@@ -853,7 +888,7 @@ export default class Inibase {
|
|
|
853
888
|
return null;
|
|
854
889
|
}
|
|
855
890
|
async sum(tableName, columns, where) {
|
|
856
|
-
let RETURN;
|
|
891
|
+
let RETURN = {};
|
|
857
892
|
const schema = await this.getTableSchema(tableName);
|
|
858
893
|
if (!schema)
|
|
859
894
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
@@ -866,7 +901,9 @@ export default class Inibase {
|
|
|
866
901
|
if (await File.isExists(columnPath)) {
|
|
867
902
|
if (where) {
|
|
868
903
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
869
|
-
RETURN[column] =
|
|
904
|
+
RETURN[column] = lineNumbers
|
|
905
|
+
? await File.sum(columnPath, lineNumbers)
|
|
906
|
+
: 0;
|
|
870
907
|
}
|
|
871
908
|
else
|
|
872
909
|
RETURN[column] = await File.sum(columnPath);
|
|
@@ -875,7 +912,7 @@ export default class Inibase {
|
|
|
875
912
|
return Array.isArray(columns) ? RETURN : Object.values(RETURN)[0];
|
|
876
913
|
}
|
|
877
914
|
async max(tableName, columns, where) {
|
|
878
|
-
let RETURN;
|
|
915
|
+
let RETURN = {};
|
|
879
916
|
const schema = await this.getTableSchema(tableName);
|
|
880
917
|
if (!schema)
|
|
881
918
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
@@ -888,7 +925,9 @@ export default class Inibase {
|
|
|
888
925
|
if (await File.isExists(columnPath)) {
|
|
889
926
|
if (where) {
|
|
890
927
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
891
|
-
RETURN[column] =
|
|
928
|
+
RETURN[column] = lineNumbers
|
|
929
|
+
? await File.max(columnPath, lineNumbers)
|
|
930
|
+
: 0;
|
|
892
931
|
}
|
|
893
932
|
else
|
|
894
933
|
RETURN[column] = await File.max(columnPath);
|
|
@@ -897,7 +936,7 @@ export default class Inibase {
|
|
|
897
936
|
return RETURN;
|
|
898
937
|
}
|
|
899
938
|
async min(tableName, columns, where) {
|
|
900
|
-
let RETURN;
|
|
939
|
+
let RETURN = {};
|
|
901
940
|
const schema = await this.getTableSchema(tableName);
|
|
902
941
|
if (!schema)
|
|
903
942
|
throw this.throwError("NO_SCHEMA", tableName);
|
|
@@ -910,7 +949,9 @@ export default class Inibase {
|
|
|
910
949
|
if (await File.isExists(columnPath)) {
|
|
911
950
|
if (where) {
|
|
912
951
|
const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
|
|
913
|
-
RETURN[column] =
|
|
952
|
+
RETURN[column] = lineNumbers
|
|
953
|
+
? await File.min(columnPath, lineNumbers)
|
|
954
|
+
: 0;
|
|
914
955
|
}
|
|
915
956
|
else
|
|
916
957
|
RETURN[column] = await File.min(columnPath);
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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
4
|
export declare const isArrayOfNulls: (input: any) => input is null[] | null[][];
|
|
5
|
-
export declare const isObject: (obj: any) =>
|
|
5
|
+
export declare const isObject: (obj: any) => obj is Record<any, any>;
|
|
6
6
|
export declare const deepMerge: (target: any, source: any) => any;
|
|
7
7
|
export declare const combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
|
|
8
8
|
export declare const isNumber: (input: any) => input is number;
|
|
@@ -21,7 +21,7 @@ export declare const validateFieldType: (value: any, fieldType: FieldType | Fiel
|
|
|
21
21
|
export declare const objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
22
22
|
export default class Utils {
|
|
23
23
|
static isNumber: (input: any) => input is number;
|
|
24
|
-
static isObject: (obj: any) =>
|
|
24
|
+
static isObject: (obj: any) => obj is Record<any, any>;
|
|
25
25
|
static isEmail: (input: any) => boolean;
|
|
26
26
|
static isDate: (input: any) => boolean;
|
|
27
27
|
static isURL: (input: any) => boolean;
|
|
@@ -30,14 +30,14 @@ export default class Utils {
|
|
|
30
30
|
static deepMerge: (target: any, source: any) => any;
|
|
31
31
|
static combineObjects: (arr: Record<string, any>[]) => Record<string, any>;
|
|
32
32
|
static isArrayOfObjects: (input: any) => input is Record<any, any>[];
|
|
33
|
-
static findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string
|
|
34
|
-
static detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType;
|
|
33
|
+
static findChangedProperties: (obj1: Record<string, string>, obj2: Record<string, string>) => Record<string, string> | null;
|
|
34
|
+
static detectFieldType: (input: any, availableTypes: FieldType[]) => FieldType | undefined;
|
|
35
35
|
static isArrayOfArrays: (input: any) => input is any[][];
|
|
36
36
|
static isBoolean: (input: any) => input is boolean;
|
|
37
37
|
static isString: (input: any) => input is string;
|
|
38
38
|
static isHTML: (input: any) => boolean;
|
|
39
39
|
static isIP: (input: any) => boolean;
|
|
40
|
-
static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[]) => boolean;
|
|
40
|
+
static validateFieldType: (value: any, fieldType: FieldType | FieldType[], fieldChildrenType?: FieldType | FieldType[] | undefined) => boolean;
|
|
41
41
|
static objectToDotNotation: (input: Record<string, any>) => Record<string, string | number | (string | number)[]>;
|
|
42
42
|
static isArrayOfNulls: (input: any) => input is null[] | null[][];
|
|
43
43
|
}
|
package/dist/utils.js
CHANGED
|
@@ -54,12 +54,10 @@ export const isEmail = (input) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(input
|
|
|
54
54
|
export const isURL = (input) => {
|
|
55
55
|
if (typeof input !== "string")
|
|
56
56
|
return false;
|
|
57
|
-
if (input[0] === "#" ||
|
|
57
|
+
if ((input[0] === "#" && !input.includes(" ")) ||
|
|
58
58
|
input.startsWith("tel:") ||
|
|
59
59
|
input.startsWith("mailto:"))
|
|
60
60
|
return true;
|
|
61
|
-
else if ("canParse" in URL)
|
|
62
|
-
return URL.canParse(input);
|
|
63
61
|
else {
|
|
64
62
|
var pattern = new RegExp("^(https?:\\/\\/)?" + // protocol
|
|
65
63
|
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain name
|
|
@@ -72,13 +70,7 @@ export const isURL = (input) => {
|
|
|
72
70
|
};
|
|
73
71
|
export const isHTML = (input) => /<\/?\s*[a-z-][^>]*\s*>|(\&(?:[\w\d]+|#\d+|#x[a-f\d]+);)/g.test(input);
|
|
74
72
|
export const isString = (input) => Object.prototype.toString.call(input) === "[object String]" &&
|
|
75
|
-
|
|
76
|
-
!isBoolean(input) &&
|
|
77
|
-
!isEmail(input) &&
|
|
78
|
-
!isDate(input) &&
|
|
79
|
-
!isURL(input) &&
|
|
80
|
-
!isIP(input) &&
|
|
81
|
-
!isHTML(input);
|
|
73
|
+
[isNumber, isBoolean, isEmail, isURL, isIP].every((fn) => !fn(input));
|
|
82
74
|
export const isIP = (input) => /^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(input);
|
|
83
75
|
export const isBoolean = (input) => typeof input === "boolean" ||
|
|
84
76
|
input === "true" ||
|
|
@@ -86,8 +78,7 @@ export const isBoolean = (input) => typeof input === "boolean" ||
|
|
|
86
78
|
input === true ||
|
|
87
79
|
input === false;
|
|
88
80
|
export const isPassword = (input) => input.length === 161;
|
|
89
|
-
export const isDate = (input) => (
|
|
90
|
-
(!isNaN(Date.parse(String(input))) && Date.parse(String(input)) >= 0);
|
|
81
|
+
export const isDate = (input) => !isNaN(new Date(input).getTime()) || !isNaN(Date.parse(input));
|
|
91
82
|
export const isValidID = (input) => {
|
|
92
83
|
return typeof input === "string" && input.length === 32;
|
|
93
84
|
};
|