inibase 1.0.0-rc.5 → 1.0.0-rc.6
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/README.md +4 -8
- package/file.ts +47 -51
- package/index.test.ts +134 -178
- package/index.ts +179 -142
- package/package.json +2 -2
- package/utils.ts +91 -35
package/index.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "
|
|
11
|
-
import { join, parse } from "path";
|
|
2
|
+
unlink,
|
|
3
|
+
rename,
|
|
4
|
+
readFile,
|
|
5
|
+
writeFile,
|
|
6
|
+
appendFile,
|
|
7
|
+
mkdir,
|
|
8
|
+
readdir,
|
|
9
|
+
} from "node:fs/promises";
|
|
10
|
+
import { join, parse } from "node:path";
|
|
12
11
|
import Utils from "./utils";
|
|
13
12
|
import File from "./file";
|
|
13
|
+
import { scryptSync } from "node:crypto";
|
|
14
14
|
|
|
15
15
|
export type Data = {
|
|
16
16
|
id?: number | string;
|
|
@@ -29,11 +29,15 @@ export type FieldType =
|
|
|
29
29
|
| "table"
|
|
30
30
|
| "object"
|
|
31
31
|
| "array"
|
|
32
|
-
| "password"
|
|
32
|
+
| "password"
|
|
33
|
+
| "html"
|
|
34
|
+
| "ip"
|
|
35
|
+
| "id";
|
|
33
36
|
type FieldDefault = {
|
|
34
37
|
id?: string | number | null | undefined;
|
|
35
38
|
key: string;
|
|
36
39
|
required?: boolean;
|
|
40
|
+
children?: any;
|
|
37
41
|
};
|
|
38
42
|
type FieldStringType = {
|
|
39
43
|
type: Exclude<FieldType, "array" | "object">;
|
|
@@ -54,7 +58,7 @@ type FieldObjectType = {
|
|
|
54
58
|
children: Schema;
|
|
55
59
|
};
|
|
56
60
|
// if "type" is array, make "array" at first place, and "number" & "string" at last place of the array
|
|
57
|
-
type Field = FieldDefault &
|
|
61
|
+
export type Field = FieldDefault &
|
|
58
62
|
(
|
|
59
63
|
| FieldStringType
|
|
60
64
|
| FieldStringArrayType
|
|
@@ -113,6 +117,7 @@ export default class Inibase {
|
|
|
113
117
|
public cache: Map<string, string>;
|
|
114
118
|
public pageInfoArray: Record<string, Record<string, number>>;
|
|
115
119
|
public pageInfo: pageInfo;
|
|
120
|
+
private salt: Buffer;
|
|
116
121
|
|
|
117
122
|
constructor(databaseName: string, mainFolder: string = ".") {
|
|
118
123
|
this.database = databaseName;
|
|
@@ -120,6 +125,7 @@ export default class Inibase {
|
|
|
120
125
|
this.cache = new Map<string, any>();
|
|
121
126
|
this.pageInfoArray = {};
|
|
122
127
|
this.pageInfo = { page: 1, per_page: 15 };
|
|
128
|
+
this.salt = scryptSync(this.databasePath, "salt", 32);
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
private throwError(
|
|
@@ -168,25 +174,40 @@ export default class Inibase {
|
|
|
168
174
|
return new Error(errorMessage);
|
|
169
175
|
}
|
|
170
176
|
|
|
171
|
-
|
|
177
|
+
private findLastIdNumber(schema: Schema): number {
|
|
178
|
+
const lastField = schema[schema.length - 1];
|
|
179
|
+
if (lastField) {
|
|
180
|
+
if (
|
|
181
|
+
(lastField.type === "array" || lastField.type === "object") &&
|
|
182
|
+
Utils.isArrayOfObjects(lastField.children)
|
|
183
|
+
)
|
|
184
|
+
return this.findLastIdNumber(lastField.children as Schema);
|
|
185
|
+
else if (lastField.id && Utils.isValidID(lastField.id))
|
|
186
|
+
return Utils.decodeID(lastField.id as string, this.salt);
|
|
187
|
+
}
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public async setTableSchema(
|
|
192
|
+
tableName: string,
|
|
193
|
+
schema: Schema
|
|
194
|
+
): Promise<void> {
|
|
172
195
|
const encodeSchema = (schema: Schema) => {
|
|
173
196
|
let RETURN: any[][] = [],
|
|
174
197
|
index = 0;
|
|
175
198
|
for (const field of schema) {
|
|
176
199
|
if (!RETURN[index]) RETURN[index] = [];
|
|
177
200
|
RETURN[index].push(
|
|
178
|
-
field.id
|
|
179
|
-
? Utils.decodeID(field.id as string, this.databasePath)
|
|
180
|
-
: null
|
|
201
|
+
field.id ? Utils.decodeID(field.id as string, this.salt) : null
|
|
181
202
|
);
|
|
182
203
|
RETURN[index].push(field.key ?? null);
|
|
183
204
|
RETURN[index].push(field.required ?? null);
|
|
184
205
|
RETURN[index].push(field.type ?? null);
|
|
185
206
|
RETURN[index].push(
|
|
186
|
-
(field
|
|
187
|
-
field.children
|
|
188
|
-
|
|
189
|
-
|
|
207
|
+
(field as any).children
|
|
208
|
+
? Utils.isArrayOfObjects((field as any).children)
|
|
209
|
+
? encodeSchema((field as any).children as Schema) ?? null
|
|
210
|
+
: (field as any).children
|
|
190
211
|
: null
|
|
191
212
|
);
|
|
192
213
|
index++;
|
|
@@ -203,44 +224,33 @@ export default class Inibase {
|
|
|
203
224
|
oldIndex++;
|
|
204
225
|
field = {
|
|
205
226
|
...field,
|
|
206
|
-
id: Utils.encodeID(oldIndex, this.
|
|
227
|
+
id: Utils.encodeID(oldIndex, this.salt),
|
|
207
228
|
};
|
|
208
|
-
} else
|
|
209
|
-
oldIndex = Utils.decodeID(field.id as string, this.databasePath);
|
|
229
|
+
} else oldIndex = Utils.decodeID(field.id as string, this.salt);
|
|
210
230
|
field.children = addIdToSchema(field.children as Schema, oldIndex);
|
|
211
231
|
oldIndex += field.children.length;
|
|
212
232
|
} else if (field.id)
|
|
213
|
-
oldIndex = Utils.decodeID(field.id as string, this.
|
|
233
|
+
oldIndex = Utils.decodeID(field.id as string, this.salt);
|
|
214
234
|
else {
|
|
215
235
|
oldIndex++;
|
|
216
236
|
field = {
|
|
217
237
|
...field,
|
|
218
|
-
id: Utils.encodeID(oldIndex, this.
|
|
238
|
+
id: Utils.encodeID(oldIndex, this.salt),
|
|
219
239
|
};
|
|
220
240
|
}
|
|
221
241
|
return field;
|
|
222
|
-
})
|
|
223
|
-
findLastIdNumber = (schema: Schema): number => {
|
|
224
|
-
const lastField = schema[schema.length - 1];
|
|
225
|
-
if (lastField) {
|
|
226
|
-
if (
|
|
227
|
-
(lastField.type === "array" || lastField.type === "object") &&
|
|
228
|
-
Utils.isArrayOfObjects(lastField.children)
|
|
229
|
-
)
|
|
230
|
-
return findLastIdNumber(lastField.children as Schema);
|
|
231
|
-
else if (lastField.id && Utils.isValidID(lastField.id))
|
|
232
|
-
return Utils.decodeID(lastField.id as string, this.databasePath);
|
|
233
|
-
}
|
|
234
|
-
return 0;
|
|
235
|
-
};
|
|
242
|
+
});
|
|
236
243
|
|
|
237
244
|
// remove id from schema
|
|
238
|
-
schema = schema.filter(
|
|
239
|
-
|
|
245
|
+
schema = schema.filter(
|
|
246
|
+
(field) => !["id", "created_at", "updated_at"].includes(field.key)
|
|
247
|
+
);
|
|
248
|
+
schema = addIdToSchema(schema, this.findLastIdNumber(schema));
|
|
240
249
|
const TablePath = join(this.databasePath, tableName),
|
|
241
250
|
TableSchemaPath = join(TablePath, "schema.inib");
|
|
242
|
-
if (!
|
|
243
|
-
|
|
251
|
+
if (!(await File.isExists(TablePath)))
|
|
252
|
+
await mkdir(TablePath, { recursive: true });
|
|
253
|
+
if (await File.isExists(TableSchemaPath)) {
|
|
244
254
|
// update columns files names based on field id
|
|
245
255
|
const schemaToIdsPath = (schema: any, prefix = "") => {
|
|
246
256
|
let RETURN: any = {};
|
|
@@ -256,35 +266,37 @@ export default class Inibase {
|
|
|
256
266
|
)
|
|
257
267
|
);
|
|
258
268
|
} else if (Utils.isValidID(field.id))
|
|
259
|
-
RETURN[Utils.decodeID(field.id, this.
|
|
260
|
-
|
|
269
|
+
RETURN[Utils.decodeID(field.id, this.salt)] = File.encodeFileName(
|
|
270
|
+
(prefix ?? "") + field.key,
|
|
271
|
+
"inib"
|
|
272
|
+
);
|
|
261
273
|
|
|
262
274
|
return RETURN;
|
|
263
275
|
},
|
|
264
276
|
replaceOldPathes = Utils.findChangedProperties(
|
|
265
|
-
schemaToIdsPath(this.getTableSchema(tableName)),
|
|
277
|
+
schemaToIdsPath(await this.getTableSchema(tableName)),
|
|
266
278
|
schemaToIdsPath(schema)
|
|
267
279
|
);
|
|
268
280
|
if (replaceOldPathes)
|
|
269
281
|
for (const [oldPath, newPath] of Object.entries(replaceOldPathes))
|
|
270
|
-
if (
|
|
271
|
-
|
|
282
|
+
if (await File.isExists(join(TablePath, oldPath)))
|
|
283
|
+
await rename(join(TablePath, oldPath), join(TablePath, newPath));
|
|
272
284
|
}
|
|
273
285
|
|
|
274
|
-
|
|
286
|
+
await writeFile(
|
|
275
287
|
join(TablePath, "schema.inib"),
|
|
276
288
|
JSON.stringify(encodeSchema(schema))
|
|
277
289
|
);
|
|
278
290
|
}
|
|
279
291
|
|
|
280
|
-
public getTableSchema(tableName: string): Schema | undefined {
|
|
292
|
+
public async getTableSchema(tableName: string): Promise<Schema | undefined> {
|
|
281
293
|
const decodeSchema = (encodedSchema: any) => {
|
|
282
294
|
return encodedSchema.map((field: any) =>
|
|
283
295
|
Array.isArray(field[0])
|
|
284
296
|
? decodeSchema(field)
|
|
285
297
|
: Object.fromEntries(
|
|
286
298
|
Object.entries({
|
|
287
|
-
id: Utils.encodeID(field[0], this.
|
|
299
|
+
id: Utils.encodeID(field[0], this.salt),
|
|
288
300
|
key: field[1],
|
|
289
301
|
required: field[2],
|
|
290
302
|
type: field[3],
|
|
@@ -298,9 +310,11 @@ export default class Inibase {
|
|
|
298
310
|
);
|
|
299
311
|
},
|
|
300
312
|
TableSchemaPath = join(this.databasePath, tableName, "schema.inib");
|
|
301
|
-
if (!
|
|
313
|
+
if (!(await File.isExists(TableSchemaPath))) return undefined;
|
|
302
314
|
if (!this.cache.has(TableSchemaPath)) {
|
|
303
|
-
const TableSchemaPathContent =
|
|
315
|
+
const TableSchemaPathContent = await readFile(TableSchemaPath, {
|
|
316
|
+
encoding: "utf8",
|
|
317
|
+
});
|
|
304
318
|
this.cache.set(
|
|
305
319
|
TableSchemaPath,
|
|
306
320
|
TableSchemaPathContent
|
|
@@ -308,14 +322,28 @@ export default class Inibase {
|
|
|
308
322
|
: ""
|
|
309
323
|
);
|
|
310
324
|
}
|
|
325
|
+
const schema = this.cache.get(TableSchemaPath) as unknown as Schema,
|
|
326
|
+
lastIdNumber = this.findLastIdNumber(schema);
|
|
311
327
|
return [
|
|
312
328
|
{
|
|
313
|
-
id: Utils.encodeID(0, this.
|
|
329
|
+
id: Utils.encodeID(0, this.salt),
|
|
314
330
|
key: "id",
|
|
315
331
|
type: "number",
|
|
316
332
|
required: true,
|
|
317
333
|
},
|
|
318
|
-
...
|
|
334
|
+
...schema,
|
|
335
|
+
{
|
|
336
|
+
id: Utils.encodeID(lastIdNumber, this.salt),
|
|
337
|
+
key: "created_at",
|
|
338
|
+
type: "date",
|
|
339
|
+
required: true,
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: Utils.encodeID(lastIdNumber + 1, this.salt),
|
|
343
|
+
key: "updated_at",
|
|
344
|
+
type: "date",
|
|
345
|
+
required: false,
|
|
346
|
+
},
|
|
319
347
|
];
|
|
320
348
|
}
|
|
321
349
|
|
|
@@ -381,16 +409,21 @@ export default class Inibase {
|
|
|
381
409
|
|
|
382
410
|
switch (fieldType) {
|
|
383
411
|
case "string":
|
|
384
|
-
|
|
385
|
-
return !Utils.isNumber(value);
|
|
412
|
+
return Utils.isString(value);
|
|
386
413
|
case "password":
|
|
387
|
-
return
|
|
414
|
+
return (
|
|
415
|
+
Utils.isNumber(value) ||
|
|
416
|
+
Utils.isString(value) ||
|
|
417
|
+
Utils.isPassword(value)
|
|
418
|
+
);
|
|
388
419
|
case "number":
|
|
389
420
|
return Utils.isNumber(value);
|
|
421
|
+
case "html":
|
|
422
|
+
return Utils.isHTML(value);
|
|
423
|
+
case "ip":
|
|
424
|
+
return Utils.isIP(value);
|
|
390
425
|
case "boolean":
|
|
391
|
-
return (
|
|
392
|
-
typeof value === "boolean" || value === "true" || value === "false"
|
|
393
|
-
);
|
|
426
|
+
return Utils.isBoolean(value);
|
|
394
427
|
case "date":
|
|
395
428
|
return Utils.isDate(value);
|
|
396
429
|
case "object":
|
|
@@ -421,10 +454,13 @@ export default class Inibase {
|
|
|
421
454
|
Utils.isNumber((value as Data).id))
|
|
422
455
|
);
|
|
423
456
|
else return Utils.isNumber(value) || Utils.isValidID(value);
|
|
457
|
+
case "id":
|
|
458
|
+
return Utils.isNumber(value) || Utils.isValidID(value);
|
|
424
459
|
default:
|
|
425
460
|
return false;
|
|
426
461
|
}
|
|
427
462
|
};
|
|
463
|
+
|
|
428
464
|
if (Utils.isArrayOfObjects(data))
|
|
429
465
|
for (const single_data of data as Data[])
|
|
430
466
|
this.validateData(single_data, schema, skipRequiredField);
|
|
@@ -437,6 +473,7 @@ export default class Inibase {
|
|
|
437
473
|
)
|
|
438
474
|
throw this.throwError("FIELD_REQUIRED", field.key);
|
|
439
475
|
if (
|
|
476
|
+
data.hasOwnProperty(field.key) &&
|
|
440
477
|
!validateFieldType(
|
|
441
478
|
data[field.key],
|
|
442
479
|
field.type,
|
|
@@ -472,7 +509,6 @@ export default class Inibase {
|
|
|
472
509
|
): Data | Data[] | number | string => {
|
|
473
510
|
if (Array.isArray(field.type))
|
|
474
511
|
field.type = Utils.detectFieldType(value, field.type);
|
|
475
|
-
|
|
476
512
|
switch (field.type) {
|
|
477
513
|
case "array":
|
|
478
514
|
if (typeof field.children === "string") {
|
|
@@ -489,16 +525,16 @@ export default class Inibase {
|
|
|
489
525
|
value.map((item: any) =>
|
|
490
526
|
Utils.isNumber(item.id)
|
|
491
527
|
? Number(item.id)
|
|
492
|
-
: Utils.decodeID(item.id, this.
|
|
528
|
+
: Utils.decodeID(item.id, this.salt)
|
|
493
529
|
);
|
|
494
530
|
} else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
495
531
|
return value.map((item: number | string) =>
|
|
496
532
|
Utils.isNumber(item)
|
|
497
533
|
? Number(item as string)
|
|
498
|
-
: Utils.decodeID(item as string, this.
|
|
534
|
+
: Utils.decodeID(item as string, this.salt)
|
|
499
535
|
);
|
|
500
536
|
} else if (Utils.isValidID(value))
|
|
501
|
-
return [Utils.decodeID(value, this.
|
|
537
|
+
return [Utils.decodeID(value, this.salt)];
|
|
502
538
|
else if (Utils.isNumber(value)) return [Number(value)];
|
|
503
539
|
} else if (data.hasOwnProperty(field.key)) return value;
|
|
504
540
|
} else if (Utils.isArrayOfObjects(field.children))
|
|
@@ -526,21 +562,28 @@ export default class Inibase {
|
|
|
526
562
|
)
|
|
527
563
|
return Utils.isNumber(value.id)
|
|
528
564
|
? Number(value.id)
|
|
529
|
-
: Utils.decodeID(value.id, this.
|
|
565
|
+
: Utils.decodeID(value.id, this.salt);
|
|
530
566
|
} else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
531
567
|
return Utils.isNumber(value)
|
|
532
568
|
? Number(value)
|
|
533
|
-
: Utils.decodeID(value, this.
|
|
569
|
+
: Utils.decodeID(value, this.salt);
|
|
534
570
|
break;
|
|
535
571
|
case "password":
|
|
536
572
|
return value.length === 161 ? value : Utils.hashPassword(value);
|
|
537
573
|
case "number":
|
|
538
574
|
return Utils.isNumber(value) ? Number(value) : null;
|
|
575
|
+
case "id":
|
|
576
|
+
return Utils.isNumber(value)
|
|
577
|
+
? Utils.encodeID(value, this.salt)
|
|
578
|
+
: value;
|
|
539
579
|
default:
|
|
540
580
|
return value;
|
|
541
581
|
}
|
|
542
582
|
return null;
|
|
543
583
|
};
|
|
584
|
+
|
|
585
|
+
this.validateData(data, schema, formatOnlyAvailiableKeys);
|
|
586
|
+
|
|
544
587
|
if (Utils.isArrayOfObjects(data))
|
|
545
588
|
return data.map((single_data: Data) =>
|
|
546
589
|
this.formatData(single_data, schema, formatOnlyAvailiableKeys)
|
|
@@ -549,7 +592,7 @@ export default class Inibase {
|
|
|
549
592
|
let RETURN: Data = {};
|
|
550
593
|
for (const field of schema) {
|
|
551
594
|
if (!data.hasOwnProperty(field.key)) {
|
|
552
|
-
if (formatOnlyAvailiableKeys) continue;
|
|
595
|
+
if (formatOnlyAvailiableKeys || !field.required) continue;
|
|
553
596
|
RETURN[field.key] = this.getDefaultValue(field);
|
|
554
597
|
continue;
|
|
555
598
|
}
|
|
@@ -676,16 +719,15 @@ export default class Inibase {
|
|
|
676
719
|
if (!options.columns) options.columns = [];
|
|
677
720
|
else if (!Array.isArray(options.columns))
|
|
678
721
|
options.columns = [options.columns];
|
|
679
|
-
|
|
680
|
-
options.columns.length &&
|
|
681
|
-
!(options.columns as string[]).includes("id")
|
|
682
|
-
)
|
|
722
|
+
if (options.columns.length && !(options.columns as string[]).includes("id"))
|
|
683
723
|
options.columns.push("id");
|
|
684
724
|
if (!options.page) options.page = 1;
|
|
685
725
|
if (!options.per_page) options.per_page = 15;
|
|
686
726
|
let RETURN!: Data | Data[] | null;
|
|
687
|
-
let schema = this.getTableSchema(tableName);
|
|
727
|
+
let schema = await this.getTableSchema(tableName);
|
|
688
728
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
729
|
+
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
730
|
+
if (!(await File.isExists(idFilePath))) return null;
|
|
689
731
|
const filterSchemaByColumns = (schema: Schema, columns: string[]): Schema =>
|
|
690
732
|
schema
|
|
691
733
|
.map((field) => {
|
|
@@ -699,12 +741,8 @@ export default class Inibase {
|
|
|
699
741
|
Utils.isArrayOfObjects(field.children) &&
|
|
700
742
|
columns.filter(
|
|
701
743
|
(column) =>
|
|
702
|
-
column.startsWith(
|
|
703
|
-
|
|
704
|
-
) ||
|
|
705
|
-
column.startsWith(
|
|
706
|
-
"!" + field.key + (field.type === "array" ? ".*." : ".")
|
|
707
|
-
)
|
|
744
|
+
column.startsWith(field.key + ".") ||
|
|
745
|
+
column.startsWith("!" + field.key + ".")
|
|
708
746
|
).length
|
|
709
747
|
) {
|
|
710
748
|
field.children = filterSchemaByColumns(
|
|
@@ -712,19 +750,10 @@ export default class Inibase {
|
|
|
712
750
|
columns
|
|
713
751
|
.filter(
|
|
714
752
|
(column) =>
|
|
715
|
-
column.startsWith(
|
|
716
|
-
|
|
717
|
-
) ||
|
|
718
|
-
column.startsWith(
|
|
719
|
-
"!" + field.key + (field.type === "array" ? ".*." : ".")
|
|
720
|
-
)
|
|
721
|
-
)
|
|
722
|
-
.map((column) =>
|
|
723
|
-
column.replace(
|
|
724
|
-
field.key + (field.type === "array" ? ".*." : "."),
|
|
725
|
-
""
|
|
726
|
-
)
|
|
753
|
+
column.startsWith(field.key + ".") ||
|
|
754
|
+
column.startsWith("!" + field.key + ".")
|
|
727
755
|
)
|
|
756
|
+
.map((column) => column.replace(field.key + ".", ""))
|
|
728
757
|
);
|
|
729
758
|
return field;
|
|
730
759
|
}
|
|
@@ -851,7 +880,7 @@ export default class Inibase {
|
|
|
851
880
|
if (RETURN[index][field.key])
|
|
852
881
|
Object.entries(item).forEach(([key, value], _index) => {
|
|
853
882
|
RETURN[index][field.key] = RETURN[index][field.key].map(
|
|
854
|
-
(_obj, _i) => ({ ..._obj, [key]: value[
|
|
883
|
+
(_obj, _i) => ({ ..._obj, [key]: value[_i] })
|
|
855
884
|
);
|
|
856
885
|
});
|
|
857
886
|
else if (Object.values(item).every(Utils.isArrayOfArrays))
|
|
@@ -903,7 +932,7 @@ export default class Inibase {
|
|
|
903
932
|
: this.getDefaultValue(field);
|
|
904
933
|
}
|
|
905
934
|
} else if (
|
|
906
|
-
|
|
935
|
+
await File.isExists(
|
|
907
936
|
join(
|
|
908
937
|
path,
|
|
909
938
|
File.encodeFileName((prefix ?? "") + field.key, "inib")
|
|
@@ -942,13 +971,13 @@ export default class Inibase {
|
|
|
942
971
|
});
|
|
943
972
|
} else if (field.type === "table") {
|
|
944
973
|
if (
|
|
945
|
-
|
|
946
|
-
|
|
974
|
+
(await File.isExists(join(this.databasePath, field.key))) &&
|
|
975
|
+
(await File.isExists(
|
|
947
976
|
join(
|
|
948
977
|
path,
|
|
949
978
|
File.encodeFileName((prefix ?? "") + field.key, "inib")
|
|
950
979
|
)
|
|
951
|
-
)
|
|
980
|
+
))
|
|
952
981
|
) {
|
|
953
982
|
if (options.columns)
|
|
954
983
|
options.columns = (options.columns as string[])
|
|
@@ -975,7 +1004,7 @@ export default class Inibase {
|
|
|
975
1004
|
}
|
|
976
1005
|
}
|
|
977
1006
|
} else if (
|
|
978
|
-
|
|
1007
|
+
await File.isExists(
|
|
979
1008
|
join(path, File.encodeFileName((prefix ?? "") + field.key, "inib"))
|
|
980
1009
|
)
|
|
981
1010
|
)
|
|
@@ -1014,18 +1043,19 @@ export default class Inibase {
|
|
|
1014
1043
|
} else if (Utils.isValidID(where) || Utils.isNumber(where)) {
|
|
1015
1044
|
let Ids = where as string | number | (string | number)[];
|
|
1016
1045
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
1017
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1018
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
1019
1046
|
const [lineNumbers, countItems] = await File.search(
|
|
1020
1047
|
idFilePath,
|
|
1021
1048
|
"[]",
|
|
1022
1049
|
Utils.isNumber(Ids)
|
|
1023
1050
|
? Ids.map((id) => Number(id as string))
|
|
1024
|
-
: Ids.map((id) => Utils.decodeID(id as string, this.
|
|
1051
|
+
: Ids.map((id) => Utils.decodeID(id as string, this.salt)),
|
|
1025
1052
|
undefined,
|
|
1026
1053
|
"number",
|
|
1027
1054
|
undefined,
|
|
1028
|
-
Ids.length
|
|
1055
|
+
Ids.length,
|
|
1056
|
+
0,
|
|
1057
|
+
false,
|
|
1058
|
+
this.databasePath
|
|
1029
1059
|
);
|
|
1030
1060
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1031
1061
|
throw this.throwError(
|
|
@@ -1240,7 +1270,8 @@ export default class Inibase {
|
|
|
1240
1270
|
(field as any)?.children,
|
|
1241
1271
|
options.per_page,
|
|
1242
1272
|
(options.page as number) - 1 * (options.per_page as number) + 1,
|
|
1243
|
-
true
|
|
1273
|
+
true,
|
|
1274
|
+
this.databasePath
|
|
1244
1275
|
);
|
|
1245
1276
|
if (searchResult) {
|
|
1246
1277
|
RETURN = Utils.deepMerge(RETURN, searchResult);
|
|
@@ -1306,12 +1337,12 @@ export default class Inibase {
|
|
|
1306
1337
|
return null;
|
|
1307
1338
|
return Utils.isArrayOfObjects(RETURN)
|
|
1308
1339
|
? (RETURN as Data[]).map((data: Data) => {
|
|
1309
|
-
data.id = Utils.encodeID(data.id as number, this.
|
|
1340
|
+
data.id = Utils.encodeID(data.id as number, this.salt);
|
|
1310
1341
|
return data;
|
|
1311
1342
|
})
|
|
1312
1343
|
: {
|
|
1313
1344
|
...(RETURN as Data),
|
|
1314
|
-
id: Utils.encodeID((RETURN as Data).id as number, this.
|
|
1345
|
+
id: Utils.encodeID((RETURN as Data).id as number, this.salt),
|
|
1315
1346
|
};
|
|
1316
1347
|
}
|
|
1317
1348
|
|
|
@@ -1323,41 +1354,38 @@ export default class Inibase {
|
|
|
1323
1354
|
per_page: 15,
|
|
1324
1355
|
}
|
|
1325
1356
|
): Promise<Data | Data[] | null> {
|
|
1326
|
-
const schema = this.getTableSchema(tableName);
|
|
1357
|
+
const schema = await this.getTableSchema(tableName);
|
|
1327
1358
|
let RETURN: Data | Data[] | null | undefined;
|
|
1328
1359
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1329
1360
|
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1330
|
-
let last_id =
|
|
1361
|
+
let last_id = (await File.isExists(idFilePath))
|
|
1331
1362
|
? Number(Object.values(await File.get(idFilePath, -1, "number"))[0])
|
|
1332
1363
|
: 0;
|
|
1333
1364
|
if (Utils.isArrayOfObjects(data))
|
|
1334
1365
|
(data as Data[]).forEach((single_data, index) => {
|
|
1335
1366
|
if (!RETURN) RETURN = [];
|
|
1336
|
-
RETURN[index] = (({ id, updated_at, created_at, ...rest }) =>
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1367
|
+
RETURN[index] = (({ id, updated_at, created_at, ...rest }) => ({
|
|
1368
|
+
id: ++last_id,
|
|
1369
|
+
...rest,
|
|
1370
|
+
created_at: new Date(),
|
|
1371
|
+
}))(single_data);
|
|
1341
1372
|
});
|
|
1342
|
-
else
|
|
1343
|
-
RETURN = (({ id, updated_at, created_at, ...rest }) =>
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1373
|
+
else
|
|
1374
|
+
RETURN = (({ id, updated_at, created_at, ...rest }) => ({
|
|
1375
|
+
id: ++last_id,
|
|
1376
|
+
...rest,
|
|
1377
|
+
created_at: new Date(),
|
|
1378
|
+
}))(data as Data);
|
|
1349
1379
|
if (!RETURN) throw this.throwError("NO_DATA");
|
|
1350
|
-
this.validateData(RETURN, schema);
|
|
1351
1380
|
RETURN = this.formatData(RETURN, schema);
|
|
1352
1381
|
const pathesContents = this.joinPathesContents(
|
|
1353
1382
|
join(this.databasePath, tableName),
|
|
1354
1383
|
RETURN
|
|
1355
1384
|
);
|
|
1356
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1357
|
-
|
|
1385
|
+
for await (const [path, content] of Object.entries(pathesContents))
|
|
1386
|
+
await appendFile(
|
|
1358
1387
|
path,
|
|
1359
|
-
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1360
|
-
"utf8"
|
|
1388
|
+
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1361
1389
|
);
|
|
1362
1390
|
|
|
1363
1391
|
return this.get(
|
|
@@ -1378,9 +1406,11 @@ export default class Inibase {
|
|
|
1378
1406
|
per_page: 15,
|
|
1379
1407
|
}
|
|
1380
1408
|
): Promise<Data | Data[] | null> {
|
|
1381
|
-
const schema = this.getTableSchema(tableName);
|
|
1409
|
+
const schema = await this.getTableSchema(tableName);
|
|
1382
1410
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1383
|
-
this.
|
|
1411
|
+
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1412
|
+
if (!(await File.isExists(idFilePath)))
|
|
1413
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1384
1414
|
data = this.formatData(data, schema, true);
|
|
1385
1415
|
if (!where) {
|
|
1386
1416
|
if (Utils.isArrayOfObjects(data)) {
|
|
@@ -1401,7 +1431,7 @@ export default class Inibase {
|
|
|
1401
1431
|
return this.put(
|
|
1402
1432
|
tableName,
|
|
1403
1433
|
data,
|
|
1404
|
-
Utils.decodeID((data as Data).id as string, this.
|
|
1434
|
+
Utils.decodeID((data as Data).id as string, this.salt)
|
|
1405
1435
|
);
|
|
1406
1436
|
} else {
|
|
1407
1437
|
const pathesContents = this.joinPathesContents(
|
|
@@ -1423,16 +1453,17 @@ export default class Inibase {
|
|
|
1423
1453
|
} else if (Utils.isValidID(where)) {
|
|
1424
1454
|
let Ids = where as string | string[];
|
|
1425
1455
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
1426
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1427
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
1428
1456
|
const [lineNumbers, countItems] = await File.search(
|
|
1429
1457
|
idFilePath,
|
|
1430
1458
|
"[]",
|
|
1431
|
-
Ids.map((id) => Utils.decodeID(id, this.
|
|
1459
|
+
Ids.map((id) => Utils.decodeID(id, this.salt)),
|
|
1432
1460
|
undefined,
|
|
1433
1461
|
"number",
|
|
1434
1462
|
undefined,
|
|
1435
|
-
Ids.length
|
|
1463
|
+
Ids.length,
|
|
1464
|
+
0,
|
|
1465
|
+
false,
|
|
1466
|
+
this.databasePath
|
|
1436
1467
|
);
|
|
1437
1468
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1438
1469
|
throw this.throwError("INVALID_ID");
|
|
@@ -1476,31 +1507,35 @@ export default class Inibase {
|
|
|
1476
1507
|
tableName: string,
|
|
1477
1508
|
where?: number | string | (number | string)[] | Criteria,
|
|
1478
1509
|
_id?: string | string[]
|
|
1479
|
-
): Promise<string | string[]> {
|
|
1480
|
-
const schema = this.getTableSchema(tableName);
|
|
1510
|
+
): Promise<string | string[] | null> {
|
|
1511
|
+
const schema = await this.getTableSchema(tableName);
|
|
1481
1512
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1513
|
+
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1514
|
+
if (!(await File.isExists(idFilePath)))
|
|
1515
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1482
1516
|
if (!where) {
|
|
1483
|
-
const files =
|
|
1517
|
+
const files = await readdir(join(this.databasePath, tableName));
|
|
1484
1518
|
if (files.length) {
|
|
1485
1519
|
for (const file in files.filter(
|
|
1486
1520
|
(fileName: string) => fileName !== "schema.inib"
|
|
1487
1521
|
))
|
|
1488
|
-
|
|
1522
|
+
await unlink(join(this.databasePath, tableName, file));
|
|
1489
1523
|
}
|
|
1490
1524
|
return "*";
|
|
1491
1525
|
} else if (Utils.isValidID(where)) {
|
|
1492
1526
|
let Ids = where as string | string[];
|
|
1493
1527
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
1494
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1495
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
1496
1528
|
const [lineNumbers, countItems] = await File.search(
|
|
1497
1529
|
idFilePath,
|
|
1498
1530
|
"[]",
|
|
1499
|
-
Ids.map((id) => Utils.decodeID(id, this.
|
|
1531
|
+
Ids.map((id) => Utils.decodeID(id, this.salt)),
|
|
1500
1532
|
undefined,
|
|
1501
1533
|
"number",
|
|
1502
1534
|
undefined,
|
|
1503
|
-
Ids.length
|
|
1535
|
+
Ids.length,
|
|
1536
|
+
0,
|
|
1537
|
+
false,
|
|
1538
|
+
this.databasePath
|
|
1504
1539
|
);
|
|
1505
1540
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1506
1541
|
throw this.throwError("INVALID_ID");
|
|
@@ -1510,7 +1545,7 @@ export default class Inibase {
|
|
|
1510
1545
|
where as string | string[]
|
|
1511
1546
|
);
|
|
1512
1547
|
} else if (Utils.isNumber(where)) {
|
|
1513
|
-
const files =
|
|
1548
|
+
const files = await readdir(join(this.databasePath, tableName));
|
|
1514
1549
|
if (files.length) {
|
|
1515
1550
|
if (!_id)
|
|
1516
1551
|
_id = Object.values(
|
|
@@ -1521,9 +1556,10 @@ export default class Inibase {
|
|
|
1521
1556
|
)
|
|
1522
1557
|
)
|
|
1523
1558
|
.map(Number)
|
|
1524
|
-
.map((id) => Utils.encodeID(id, this.
|
|
1525
|
-
for (const file
|
|
1526
|
-
(fileName: string) =>
|
|
1559
|
+
.map((id) => Utils.encodeID(id, this.salt));
|
|
1560
|
+
for (const file of files.filter(
|
|
1561
|
+
(fileName: string) =>
|
|
1562
|
+
fileName.endsWith(".inib") && fileName !== "schema.inib"
|
|
1527
1563
|
))
|
|
1528
1564
|
await File.remove(
|
|
1529
1565
|
join(this.databasePath, tableName, file),
|
|
@@ -1537,5 +1573,6 @@ export default class Inibase {
|
|
|
1537
1573
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1538
1574
|
return this.delete(tableName, lineNumbers);
|
|
1539
1575
|
} else throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
1576
|
+
return null;
|
|
1540
1577
|
}
|
|
1541
1578
|
}
|