inibase 1.0.0-rc.11 → 1.0.0-rc.12
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/.env.example +1 -0
- package/README.md +50 -0
- package/file.ts +134 -4
- package/index.test.ts +2 -1
- package/index.ts +441 -364
- package/package.json +2 -1
- package/utils.ts +174 -20
- package/utils.server.ts +0 -79
package/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
rename,
|
|
4
4
|
readFile,
|
|
5
5
|
writeFile,
|
|
6
|
-
appendFile,
|
|
7
6
|
mkdir,
|
|
8
7
|
readdir,
|
|
9
8
|
} from "node:fs/promises";
|
|
@@ -11,14 +10,13 @@ import { join, parse } from "node:path";
|
|
|
11
10
|
import { scryptSync } from "node:crypto";
|
|
12
11
|
import File from "./file";
|
|
13
12
|
import Utils from "./utils";
|
|
14
|
-
import UtilsServer from "./utils.server";
|
|
15
13
|
|
|
16
|
-
export
|
|
14
|
+
export interface Data {
|
|
17
15
|
id?: number | string;
|
|
18
16
|
[key: string]: any;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
17
|
+
createdAt?: Date;
|
|
18
|
+
updatedAt?: Date;
|
|
19
|
+
}
|
|
22
20
|
|
|
23
21
|
export type FieldType =
|
|
24
22
|
| "string"
|
|
@@ -74,6 +72,7 @@ export interface Options {
|
|
|
74
72
|
page?: number;
|
|
75
73
|
per_page?: number;
|
|
76
74
|
columns?: string[] | string;
|
|
75
|
+
order?: Record<string, "asc" | "desc">;
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
export type ComparisonOperator =
|
|
@@ -94,12 +93,11 @@ type pageInfo = {
|
|
|
94
93
|
} & Options;
|
|
95
94
|
|
|
96
95
|
export type Criteria =
|
|
97
|
-
| {
|
|
96
|
+
| ({
|
|
98
97
|
[logic in "and" | "or"]?: Criteria | (string | number | boolean | null)[];
|
|
99
|
-
}
|
|
100
|
-
| {
|
|
98
|
+
} & {
|
|
101
99
|
[key: string]: string | number | boolean | Criteria;
|
|
102
|
-
}
|
|
100
|
+
})
|
|
103
101
|
| null;
|
|
104
102
|
|
|
105
103
|
declare global {
|
|
@@ -119,7 +117,7 @@ export default class Inibase {
|
|
|
119
117
|
public pageInfo: pageInfo;
|
|
120
118
|
private cache: Map<string, string>;
|
|
121
119
|
private totalItems: Record<string, number>;
|
|
122
|
-
|
|
120
|
+
public salt: Buffer;
|
|
123
121
|
|
|
124
122
|
constructor(database: string, mainFolder: string = ".") {
|
|
125
123
|
this.database = database;
|
|
@@ -128,7 +126,11 @@ export default class Inibase {
|
|
|
128
126
|
this.cache = new Map<string, any>();
|
|
129
127
|
this.totalItems = {};
|
|
130
128
|
this.pageInfo = { page: 1, per_page: 15 };
|
|
131
|
-
this.salt = scryptSync(
|
|
129
|
+
this.salt = scryptSync(
|
|
130
|
+
process.env.INIBASE_SECRET ?? "inibase",
|
|
131
|
+
(process.env.INIBASE_SECRET ?? "inibase") + "_salt",
|
|
132
|
+
32
|
|
133
|
+
);
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
private throwError(
|
|
@@ -177,100 +179,46 @@ export default class Inibase {
|
|
|
177
179
|
return new Error(errorMessage);
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
private findLastIdNumber(schema: Schema): number {
|
|
181
|
-
const lastField = schema[schema.length - 1];
|
|
182
|
-
if (lastField) {
|
|
183
|
-
if (
|
|
184
|
-
(lastField.type === "array" || lastField.type === "object") &&
|
|
185
|
-
Utils.isArrayOfObjects(lastField.children)
|
|
186
|
-
)
|
|
187
|
-
return this.findLastIdNumber(lastField.children as Schema);
|
|
188
|
-
else if (lastField.id && Utils.isValidID(lastField.id))
|
|
189
|
-
return UtilsServer.decodeID(lastField.id as string, this.salt);
|
|
190
|
-
}
|
|
191
|
-
return 0;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
182
|
public async setTableSchema(
|
|
195
183
|
tableName: string,
|
|
196
184
|
schema: Schema
|
|
197
185
|
): Promise<void> {
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
: null
|
|
207
|
-
);
|
|
208
|
-
RETURN[index].push(field.key ?? null);
|
|
209
|
-
RETURN[index].push(field.required ?? null);
|
|
210
|
-
RETURN[index].push(field.type ?? null);
|
|
211
|
-
RETURN[index].push(
|
|
212
|
-
(field as any).children
|
|
213
|
-
? Utils.isArrayOfObjects((field as any).children)
|
|
214
|
-
? encodeSchema((field as any).children as Schema) ?? null
|
|
215
|
-
: (field as any).children
|
|
216
|
-
: null
|
|
217
|
-
);
|
|
218
|
-
index++;
|
|
219
|
-
}
|
|
220
|
-
return RETURN;
|
|
221
|
-
},
|
|
222
|
-
addIdToSchema = (schema: Schema, oldIndex: number = 0) =>
|
|
223
|
-
schema.map((field) => {
|
|
224
|
-
if (
|
|
225
|
-
(field.type === "array" || field.type === "object") &&
|
|
226
|
-
Utils.isArrayOfObjects(field.children)
|
|
227
|
-
) {
|
|
228
|
-
if (!field.id) {
|
|
229
|
-
oldIndex++;
|
|
230
|
-
field = {
|
|
231
|
-
...field,
|
|
232
|
-
id: UtilsServer.encodeID(oldIndex, this.salt),
|
|
233
|
-
};
|
|
234
|
-
} else
|
|
235
|
-
oldIndex = UtilsServer.decodeID(field.id as string, this.salt);
|
|
236
|
-
field.children = addIdToSchema(field.children as Schema, oldIndex);
|
|
237
|
-
oldIndex += field.children.length;
|
|
238
|
-
} else if (field.id)
|
|
239
|
-
oldIndex = UtilsServer.decodeID(field.id as string, this.salt);
|
|
240
|
-
else {
|
|
241
|
-
oldIndex++;
|
|
242
|
-
field = {
|
|
243
|
-
...field,
|
|
244
|
-
id: UtilsServer.encodeID(oldIndex, this.salt),
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
return field;
|
|
248
|
-
});
|
|
249
|
-
|
|
186
|
+
const decodeIdFromSchema = (schema: Schema) =>
|
|
187
|
+
schema.map((field) => {
|
|
188
|
+
if (field.children && Utils.isArrayOfObjects(field.children))
|
|
189
|
+
field.children = decodeIdFromSchema(field.children as Schema);
|
|
190
|
+
if (!Utils.isNumber(field.id))
|
|
191
|
+
field.id = Utils.decodeID(field.id, this.salt);
|
|
192
|
+
return field;
|
|
193
|
+
});
|
|
250
194
|
// remove id from schema
|
|
251
195
|
schema = schema.filter(
|
|
252
|
-
(
|
|
196
|
+
({ key }) => !["id", "createdAt", "updatedAt"].includes(key)
|
|
197
|
+
);
|
|
198
|
+
schema = Utils.addIdToSchema(
|
|
199
|
+
schema,
|
|
200
|
+
Utils.findLastIdNumber(schema, this.salt),
|
|
201
|
+
this.salt
|
|
253
202
|
);
|
|
254
|
-
schema = addIdToSchema(schema, this.findLastIdNumber(schema));
|
|
255
203
|
const TablePath = join(this.folder, this.database, tableName),
|
|
256
|
-
TableSchemaPath = join(TablePath, "schema");
|
|
204
|
+
TableSchemaPath = join(TablePath, "schema.json");
|
|
257
205
|
if (!(await File.isExists(TablePath)))
|
|
258
206
|
await mkdir(TablePath, { recursive: true });
|
|
259
207
|
if (await File.isExists(TableSchemaPath)) {
|
|
260
208
|
// update columns files names based on field id
|
|
261
|
-
const schemaToIdsPath = (schema:
|
|
209
|
+
const schemaToIdsPath = (schema: Schema, prefix = "") => {
|
|
262
210
|
let RETURN: any = {};
|
|
263
211
|
for (const field of schema)
|
|
264
212
|
if (field.children && Utils.isArrayOfObjects(field.children)) {
|
|
265
213
|
Utils.deepMerge(
|
|
266
214
|
RETURN,
|
|
267
215
|
schemaToIdsPath(
|
|
268
|
-
field.children,
|
|
216
|
+
field.children as Schema,
|
|
269
217
|
(prefix ?? "") + field.key + "."
|
|
270
218
|
)
|
|
271
219
|
);
|
|
272
220
|
} else if (Utils.isValidID(field.id))
|
|
273
|
-
RETURN[
|
|
221
|
+
RETURN[Utils.decodeID(field.id, this.salt)] =
|
|
274
222
|
(prefix ?? "") + field.key + ".inib";
|
|
275
223
|
|
|
276
224
|
return RETURN;
|
|
@@ -286,63 +234,44 @@ export default class Inibase {
|
|
|
286
234
|
}
|
|
287
235
|
|
|
288
236
|
await writeFile(
|
|
289
|
-
join(TablePath, "schema"),
|
|
290
|
-
JSON.stringify(
|
|
237
|
+
join(TablePath, "schema.json"),
|
|
238
|
+
JSON.stringify(decodeIdFromSchema(schema))
|
|
291
239
|
);
|
|
292
240
|
}
|
|
293
241
|
|
|
294
242
|
public async getTableSchema(tableName: string): Promise<Schema | undefined> {
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
id: UtilsServer.encodeID(field[0], this.salt),
|
|
302
|
-
key: field[1],
|
|
303
|
-
required: field[2],
|
|
304
|
-
type: field[3],
|
|
305
|
-
children: field[4]
|
|
306
|
-
? Array.isArray(field[4])
|
|
307
|
-
? decodeSchema(field[4])
|
|
308
|
-
: field[4]
|
|
309
|
-
: null,
|
|
310
|
-
}).filter(([_, v]) => v != null)
|
|
311
|
-
)
|
|
312
|
-
);
|
|
313
|
-
},
|
|
314
|
-
TableSchemaPath = join(this.folder, this.database, tableName, "schema");
|
|
243
|
+
const TableSchemaPath = join(
|
|
244
|
+
this.folder,
|
|
245
|
+
this.database,
|
|
246
|
+
tableName,
|
|
247
|
+
"schema.json"
|
|
248
|
+
);
|
|
315
249
|
if (!(await File.isExists(TableSchemaPath))) return undefined;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
: ""
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
const schema = this.cache.get(TableSchemaPath) as unknown as Schema,
|
|
328
|
-
lastIdNumber = this.findLastIdNumber(schema);
|
|
250
|
+
|
|
251
|
+
if (!this.cache.has(TableSchemaPath))
|
|
252
|
+
this.cache.set(TableSchemaPath, await readFile(TableSchemaPath, "utf8"));
|
|
253
|
+
|
|
254
|
+
if (!this.cache.get(TableSchemaPath)) return undefined;
|
|
255
|
+
const schema = JSON.parse(this.cache.get(TableSchemaPath)),
|
|
256
|
+
lastIdNumber = Utils.findLastIdNumber(schema, this.salt);
|
|
257
|
+
|
|
329
258
|
return [
|
|
330
259
|
{
|
|
331
|
-
id:
|
|
260
|
+
id: Utils.encodeID(0, this.salt),
|
|
332
261
|
key: "id",
|
|
333
262
|
type: "id",
|
|
334
263
|
required: true,
|
|
335
264
|
},
|
|
336
|
-
...schema,
|
|
265
|
+
...Utils.addIdToSchema(schema, lastIdNumber, this.salt),
|
|
337
266
|
{
|
|
338
|
-
id:
|
|
339
|
-
key: "
|
|
267
|
+
id: Utils.encodeID(lastIdNumber + 1, this.salt),
|
|
268
|
+
key: "createdAt",
|
|
340
269
|
type: "date",
|
|
341
270
|
required: true,
|
|
342
271
|
},
|
|
343
272
|
{
|
|
344
|
-
id:
|
|
345
|
-
key: "
|
|
273
|
+
id: Utils.encodeID(lastIdNumber + 2, this.salt),
|
|
274
|
+
key: "updatedAt",
|
|
346
275
|
type: "date",
|
|
347
276
|
required: false,
|
|
348
277
|
},
|
|
@@ -394,81 +323,76 @@ export default class Inibase {
|
|
|
394
323
|
for (const single_data of data as Data[])
|
|
395
324
|
this.validateData(single_data, schema, skipRequiredField);
|
|
396
325
|
else if (Utils.isObject(data)) {
|
|
397
|
-
for (const
|
|
326
|
+
for (const { key, type, required, children } of schema) {
|
|
327
|
+
if (!data.hasOwnProperty(key) && required && !skipRequiredField)
|
|
328
|
+
throw this.throwError("FIELD_REQUIRED", key);
|
|
398
329
|
if (
|
|
399
|
-
|
|
400
|
-
field.required &&
|
|
401
|
-
!skipRequiredField
|
|
402
|
-
)
|
|
403
|
-
throw this.throwError("FIELD_REQUIRED", field.key);
|
|
404
|
-
if (
|
|
405
|
-
data.hasOwnProperty(field.key) &&
|
|
330
|
+
data.hasOwnProperty(key) &&
|
|
406
331
|
!Utils.validateFieldType(
|
|
407
|
-
data[
|
|
408
|
-
|
|
409
|
-
(
|
|
410
|
-
!Utils.isArrayOfObjects((field as any)?.children)
|
|
411
|
-
? (field as any)?.children
|
|
412
|
-
: undefined
|
|
332
|
+
data[key],
|
|
333
|
+
type,
|
|
334
|
+
children && !Utils.isArrayOfObjects(children) ? children : undefined
|
|
413
335
|
)
|
|
414
336
|
)
|
|
415
|
-
throw this.throwError("INVALID_TYPE",
|
|
337
|
+
throw this.throwError("INVALID_TYPE", key);
|
|
416
338
|
if (
|
|
417
|
-
(
|
|
418
|
-
|
|
419
|
-
Utils.isArrayOfObjects(
|
|
339
|
+
(type === "array" || type === "object") &&
|
|
340
|
+
children &&
|
|
341
|
+
Utils.isArrayOfObjects(children)
|
|
420
342
|
)
|
|
421
|
-
this.validateData(
|
|
422
|
-
data[field.key],
|
|
423
|
-
field.children as Schema,
|
|
424
|
-
skipRequiredField
|
|
425
|
-
);
|
|
343
|
+
this.validateData(data[key], children as Schema, skipRequiredField);
|
|
426
344
|
}
|
|
427
345
|
}
|
|
428
346
|
}
|
|
429
347
|
|
|
430
|
-
public formatData(
|
|
431
|
-
data:
|
|
348
|
+
public formatData<dataType extends Data | Data[]>(
|
|
349
|
+
data: dataType,
|
|
432
350
|
schema: Schema,
|
|
433
351
|
formatOnlyAvailiableKeys?: boolean
|
|
434
|
-
): Data
|
|
352
|
+
): dataType extends Data ? Data : Data[] {
|
|
353
|
+
this.validateData(data, schema, formatOnlyAvailiableKeys);
|
|
354
|
+
|
|
435
355
|
const formatField = (
|
|
436
|
-
value:
|
|
356
|
+
value: Data | number | string | (number | string | Data)[],
|
|
437
357
|
field: Field
|
|
438
358
|
): Data | Data[] | number | string => {
|
|
439
359
|
if (Array.isArray(field.type))
|
|
440
360
|
field.type = Utils.detectFieldType(value, field.type);
|
|
441
361
|
switch (field.type) {
|
|
442
362
|
case "array":
|
|
363
|
+
if (!Array.isArray(value)) value = [value];
|
|
443
364
|
if (typeof field.children === "string") {
|
|
444
365
|
if (field.type === "array" && field.children === "table") {
|
|
445
|
-
if (Array.isArray(
|
|
446
|
-
if (Utils.isArrayOfObjects(
|
|
366
|
+
if (Array.isArray(value)) {
|
|
367
|
+
if (Utils.isArrayOfObjects(value)) {
|
|
447
368
|
if (
|
|
448
369
|
value.every(
|
|
449
|
-
(item: any) =>
|
|
370
|
+
(item: any): item is Data =>
|
|
450
371
|
item.hasOwnProperty("id") &&
|
|
451
372
|
(Utils.isValidID(item.id) || Utils.isNumber(item.id))
|
|
452
373
|
)
|
|
453
374
|
)
|
|
454
|
-
value.map((item
|
|
375
|
+
value.map((item) =>
|
|
455
376
|
Utils.isNumber(item.id)
|
|
456
377
|
? Number(item.id)
|
|
457
|
-
:
|
|
378
|
+
: Utils.decodeID(item.id, this.salt)
|
|
458
379
|
);
|
|
459
|
-
} else if (
|
|
460
|
-
|
|
380
|
+
} else if (
|
|
381
|
+
(value as (number | string)[]).every(Utils.isValidID) ||
|
|
382
|
+
(value as (number | string)[]).every(Utils.isNumber)
|
|
383
|
+
)
|
|
384
|
+
return (value as (number | string)[]).map((item) =>
|
|
461
385
|
Utils.isNumber(item)
|
|
462
|
-
? Number(item
|
|
463
|
-
:
|
|
386
|
+
? Number(item)
|
|
387
|
+
: Utils.decodeID(item, this.salt)
|
|
464
388
|
);
|
|
465
389
|
} else if (Utils.isValidID(value))
|
|
466
|
-
return [
|
|
390
|
+
return [Utils.decodeID(value, this.salt)];
|
|
467
391
|
else if (Utils.isNumber(value)) return [Number(value)];
|
|
468
392
|
} else if (data.hasOwnProperty(field.key)) return value;
|
|
469
393
|
} else if (Utils.isArrayOfObjects(field.children))
|
|
470
394
|
return this.formatData(
|
|
471
|
-
value,
|
|
395
|
+
value as Data[],
|
|
472
396
|
field.children as Schema,
|
|
473
397
|
formatOnlyAvailiableKeys
|
|
474
398
|
);
|
|
@@ -478,41 +402,46 @@ export default class Inibase {
|
|
|
478
402
|
case "object":
|
|
479
403
|
if (Utils.isArrayOfObjects(field.children))
|
|
480
404
|
return this.formatData(
|
|
481
|
-
value,
|
|
482
|
-
field.children,
|
|
405
|
+
value as Data,
|
|
406
|
+
field.children as Schema,
|
|
483
407
|
formatOnlyAvailiableKeys
|
|
484
408
|
);
|
|
485
409
|
break;
|
|
486
410
|
case "table":
|
|
411
|
+
if (Array.isArray(value)) value = value[0];
|
|
487
412
|
if (Utils.isObject(value)) {
|
|
488
413
|
if (
|
|
489
|
-
value.hasOwnProperty("id") &&
|
|
490
|
-
(Utils.isValidID(value.id) ||
|
|
414
|
+
(value as Data).hasOwnProperty("id") &&
|
|
415
|
+
(Utils.isValidID((value as Data).id) ||
|
|
416
|
+
Utils.isNumber((value as Data).id))
|
|
491
417
|
)
|
|
492
|
-
return Utils.isNumber(value.id)
|
|
493
|
-
? Number(value.id)
|
|
494
|
-
:
|
|
418
|
+
return Utils.isNumber((value as Data).id)
|
|
419
|
+
? Number((value as Data).id)
|
|
420
|
+
: Utils.decodeID((value as Data).id as string, this.salt);
|
|
495
421
|
} else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
496
422
|
return Utils.isNumber(value)
|
|
497
423
|
? Number(value)
|
|
498
|
-
:
|
|
424
|
+
: Utils.decodeID(value, this.salt);
|
|
499
425
|
break;
|
|
500
426
|
case "password":
|
|
501
|
-
|
|
427
|
+
if (Array.isArray(value)) value = value[0];
|
|
428
|
+
return typeof value === "string" && value.length === 161
|
|
429
|
+
? value
|
|
430
|
+
: Utils.hashPassword(String(value));
|
|
502
431
|
case "number":
|
|
432
|
+
if (Array.isArray(value)) value = value[0];
|
|
503
433
|
return Utils.isNumber(value) ? Number(value) : null;
|
|
504
434
|
case "id":
|
|
435
|
+
if (Array.isArray(value)) value = value[0];
|
|
505
436
|
return Utils.isNumber(value)
|
|
506
437
|
? value
|
|
507
|
-
:
|
|
438
|
+
: Utils.decodeID(value as string, this.salt);
|
|
508
439
|
default:
|
|
509
440
|
return value;
|
|
510
441
|
}
|
|
511
442
|
return null;
|
|
512
443
|
};
|
|
513
444
|
|
|
514
|
-
this.validateData(data, schema, formatOnlyAvailiableKeys);
|
|
515
|
-
|
|
516
445
|
if (Utils.isArrayOfObjects(data))
|
|
517
446
|
return data.map((single_data: Data) =>
|
|
518
447
|
this.formatData(single_data, schema, formatOnlyAvailiableKeys)
|
|
@@ -556,7 +485,9 @@ export default class Inibase {
|
|
|
556
485
|
: [];
|
|
557
486
|
case "object":
|
|
558
487
|
return Utils.combineObjects(
|
|
559
|
-
field.children.map((f) => ({
|
|
488
|
+
field.children.map((f: Field) => ({
|
|
489
|
+
[f.key]: this.getDefaultValue(f),
|
|
490
|
+
}))
|
|
560
491
|
);
|
|
561
492
|
case "boolean":
|
|
562
493
|
return false;
|
|
@@ -589,34 +520,26 @@ export default class Inibase {
|
|
|
589
520
|
for (const [key, value] of Object.entries(_data as Data)) {
|
|
590
521
|
if (Utils.isObject(value))
|
|
591
522
|
Object.assign(RETURN, CombineData(value, `${key}.`));
|
|
592
|
-
else if (
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
else {
|
|
613
|
-
RETURN[(prefix ?? "") + key] = File.encode(value) as
|
|
614
|
-
| boolean
|
|
615
|
-
| number
|
|
616
|
-
| string
|
|
617
|
-
| null;
|
|
618
|
-
}
|
|
619
|
-
} else
|
|
523
|
+
else if (Utils.isArrayOfObjects(value)) {
|
|
524
|
+
Object.assign(
|
|
525
|
+
RETURN,
|
|
526
|
+
CombineData(
|
|
527
|
+
combineObjectsToArray(value),
|
|
528
|
+
(prefix ?? "") + key + "."
|
|
529
|
+
)
|
|
530
|
+
);
|
|
531
|
+
} else if (
|
|
532
|
+
Utils.isArrayOfArrays(value) &&
|
|
533
|
+
value.every(Utils.isArrayOfObjects)
|
|
534
|
+
)
|
|
535
|
+
Object.assign(
|
|
536
|
+
RETURN,
|
|
537
|
+
CombineData(
|
|
538
|
+
combineObjectsToArray(value.map(combineObjectsToArray)),
|
|
539
|
+
(prefix ?? "") + key + "."
|
|
540
|
+
)
|
|
541
|
+
);
|
|
542
|
+
else
|
|
620
543
|
RETURN[(prefix ?? "") + key] = File.encode(value) as
|
|
621
544
|
| boolean
|
|
622
545
|
| number
|
|
@@ -636,29 +559,18 @@ export default class Inibase {
|
|
|
636
559
|
return addPathToKeys(CombineData(data), mainPath);
|
|
637
560
|
}
|
|
638
561
|
|
|
639
|
-
public async
|
|
640
|
-
tableName: string,
|
|
641
|
-
where?: string | number | (string | number)[] | Criteria,
|
|
642
|
-
options: Options = {
|
|
643
|
-
page: 1,
|
|
644
|
-
per_page: 15,
|
|
645
|
-
}
|
|
646
|
-
): Promise<Data | null> {
|
|
647
|
-
const _get = await this.get(tableName, where, options);
|
|
648
|
-
if (!_get) return null;
|
|
649
|
-
else if (Array.isArray(_get)) return (_get as Data)[0];
|
|
650
|
-
else return _get;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
public async get(
|
|
562
|
+
public async get<O extends boolean = false, N extends boolean = false>(
|
|
654
563
|
tableName: string,
|
|
655
564
|
where?: string | number | (string | number)[] | Criteria,
|
|
656
565
|
options: Options = {
|
|
657
566
|
page: 1,
|
|
658
567
|
per_page: 15,
|
|
659
568
|
},
|
|
660
|
-
|
|
661
|
-
|
|
569
|
+
onlyOne?: O,
|
|
570
|
+
onlyLinesNumbers?: N
|
|
571
|
+
): Promise<
|
|
572
|
+
(N extends true ? number[] : O extends true ? Data : Data[]) | null
|
|
573
|
+
> {
|
|
662
574
|
if (!options.columns) options.columns = [];
|
|
663
575
|
else if (!Array.isArray(options.columns))
|
|
664
576
|
options.columns = [options.columns];
|
|
@@ -777,19 +689,21 @@ export default class Inibase {
|
|
|
777
689
|
if (!RETURN[index][field.key][_i][child_field.key])
|
|
778
690
|
RETURN[index][field.key][_i][child_field.key] =
|
|
779
691
|
[];
|
|
780
|
-
value[_i].forEach(
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
692
|
+
value[_i].forEach(
|
|
693
|
+
(_element: any, _index: string | number) => {
|
|
694
|
+
if (
|
|
695
|
+
!RETURN[index][field.key][_i][
|
|
696
|
+
child_field.key
|
|
697
|
+
][_index]
|
|
698
|
+
)
|
|
699
|
+
RETURN[index][field.key][_i][child_field.key][
|
|
700
|
+
_index
|
|
701
|
+
] = {};
|
|
786
702
|
RETURN[index][field.key][_i][child_field.key][
|
|
787
703
|
_index
|
|
788
|
-
] =
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
][key] = _element;
|
|
792
|
-
});
|
|
704
|
+
][key] = _element;
|
|
705
|
+
}
|
|
706
|
+
);
|
|
793
707
|
}
|
|
794
708
|
}
|
|
795
709
|
);
|
|
@@ -808,6 +722,7 @@ export default class Inibase {
|
|
|
808
722
|
!Utils.isArrayOfObjects(children.children)
|
|
809
723
|
);
|
|
810
724
|
}
|
|
725
|
+
|
|
811
726
|
Object.entries(
|
|
812
727
|
(await getItemsFromSchema(
|
|
813
728
|
path,
|
|
@@ -823,7 +738,10 @@ export default class Inibase {
|
|
|
823
738
|
if (RETURN[index][field.key])
|
|
824
739
|
Object.entries(item).forEach(([key, value], _index) => {
|
|
825
740
|
RETURN[index][field.key] = RETURN[index][field.key].map(
|
|
826
|
-
(_obj, _i) => ({
|
|
741
|
+
(_obj: any, _i: string | number) => ({
|
|
742
|
+
..._obj,
|
|
743
|
+
[key]: value[_i],
|
|
744
|
+
})
|
|
827
745
|
);
|
|
828
746
|
});
|
|
829
747
|
else if (Object.values(item).every(Utils.isArrayOfArrays))
|
|
@@ -975,15 +893,20 @@ export default class Inibase {
|
|
|
975
893
|
)
|
|
976
894
|
)
|
|
977
895
|
);
|
|
978
|
-
} else if (
|
|
896
|
+
} else if (
|
|
897
|
+
(Array.isArray(where) &&
|
|
898
|
+
(where.every(Utils.isValidID) || where.every(Utils.isNumber))) ||
|
|
899
|
+
Utils.isValidID(where) ||
|
|
900
|
+
Utils.isNumber(where)
|
|
901
|
+
) {
|
|
979
902
|
let Ids = where as string | number | (string | number)[];
|
|
980
903
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
981
904
|
const [lineNumbers, countItems] = await File.search(
|
|
982
905
|
idFilePath,
|
|
983
906
|
"[]",
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
907
|
+
Ids.map((id) =>
|
|
908
|
+
Utils.isNumber(id) ? Number(id) : Utils.decodeID(id, this.salt)
|
|
909
|
+
),
|
|
987
910
|
undefined,
|
|
988
911
|
"number",
|
|
989
912
|
undefined,
|
|
@@ -997,6 +920,9 @@ export default class Inibase {
|
|
|
997
920
|
"INVALID_ID",
|
|
998
921
|
where as number | string | (number | string)[]
|
|
999
922
|
);
|
|
923
|
+
|
|
924
|
+
if (onlyLinesNumbers) return Object.keys(lineNumbers).map(Number) as any;
|
|
925
|
+
|
|
1000
926
|
RETURN = Object.values(
|
|
1001
927
|
(await getItemsFromSchema(
|
|
1002
928
|
join(this.folder, this.database, tableName),
|
|
@@ -1230,20 +1156,20 @@ export default class Inibase {
|
|
|
1230
1156
|
|
|
1231
1157
|
RETURN = await applyCriteria(where as Criteria);
|
|
1232
1158
|
if (RETURN) {
|
|
1233
|
-
if (onlyLinesNumbers) return Object.keys(RETURN).map(Number);
|
|
1159
|
+
if (onlyLinesNumbers) return Object.keys(RETURN).map(Number) as any;
|
|
1234
1160
|
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]).map(
|
|
1235
1161
|
(key) => parse(key).name
|
|
1236
1162
|
);
|
|
1237
1163
|
RETURN = Object.values(
|
|
1238
1164
|
Utils.deepMerge(
|
|
1165
|
+
RETURN,
|
|
1239
1166
|
await getItemsFromSchema(
|
|
1240
1167
|
join(this.folder, this.database, tableName),
|
|
1241
1168
|
schema.filter(
|
|
1242
1169
|
(field) => !alreadyExistsColumns.includes(field.key)
|
|
1243
1170
|
),
|
|
1244
1171
|
Object.keys(RETURN).map(Number)
|
|
1245
|
-
)
|
|
1246
|
-
RETURN
|
|
1172
|
+
)
|
|
1247
1173
|
)
|
|
1248
1174
|
);
|
|
1249
1175
|
}
|
|
@@ -1265,43 +1191,44 @@ export default class Inibase {
|
|
|
1265
1191
|
total_pages: Math.ceil(greatestTotalItems / options.per_page),
|
|
1266
1192
|
total: greatestTotalItems,
|
|
1267
1193
|
};
|
|
1268
|
-
return RETURN;
|
|
1194
|
+
return onlyOne ? RETURN[0] : RETURN;
|
|
1269
1195
|
}
|
|
1270
1196
|
|
|
1271
|
-
public async post(
|
|
1197
|
+
public async post<DataType extends Data | Data[]>(
|
|
1272
1198
|
tableName: string,
|
|
1273
|
-
data:
|
|
1199
|
+
data: DataType,
|
|
1274
1200
|
options: Options = {
|
|
1275
1201
|
page: 1,
|
|
1276
1202
|
per_page: 15,
|
|
1277
1203
|
},
|
|
1278
1204
|
returnPostedData: boolean = true
|
|
1279
|
-
): Promise<
|
|
1205
|
+
): Promise<
|
|
1206
|
+
DataType extends Data ? Data | null | void : Data[] | null | void
|
|
1207
|
+
> {
|
|
1280
1208
|
const schema = await this.getTableSchema(tableName);
|
|
1281
1209
|
let RETURN: Data | Data[] | null | undefined;
|
|
1282
1210
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1283
1211
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
: 0;
|
|
1212
|
+
|
|
1213
|
+
let [last_line_number, last_id] = (await File.isExists(idFilePath))
|
|
1214
|
+
? (Object.entries(
|
|
1215
|
+
(await File.get(idFilePath, -1, "number", undefined, this.salt))[0]
|
|
1216
|
+
)[0] as [number, number] | undefined) ?? [1, 0]
|
|
1217
|
+
: [1, 0];
|
|
1291
1218
|
if (Utils.isArrayOfObjects(data))
|
|
1292
|
-
|
|
1219
|
+
data.forEach((single_data: any, index: string | number) => {
|
|
1293
1220
|
if (!RETURN) RETURN = [];
|
|
1294
|
-
RETURN[index] = (({ id,
|
|
1221
|
+
RETURN[index] = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
1295
1222
|
id: ++last_id,
|
|
1296
1223
|
...rest,
|
|
1297
|
-
|
|
1224
|
+
createdAt: new Date(),
|
|
1298
1225
|
}))(single_data);
|
|
1299
1226
|
});
|
|
1300
1227
|
else
|
|
1301
|
-
RETURN = (({ id,
|
|
1228
|
+
RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
1302
1229
|
id: ++last_id,
|
|
1303
1230
|
...rest,
|
|
1304
|
-
|
|
1231
|
+
createdAt: new Date(),
|
|
1305
1232
|
}))(data as Data);
|
|
1306
1233
|
if (!RETURN) throw this.throwError("NO_DATA");
|
|
1307
1234
|
|
|
@@ -1311,10 +1238,7 @@ export default class Inibase {
|
|
|
1311
1238
|
RETURN
|
|
1312
1239
|
);
|
|
1313
1240
|
for await (const [path, content] of Object.entries(pathesContents))
|
|
1314
|
-
await
|
|
1315
|
-
path,
|
|
1316
|
-
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1317
|
-
);
|
|
1241
|
+
await File.replace(path, { [last_line_number]: content });
|
|
1318
1242
|
|
|
1319
1243
|
if (returnPostedData)
|
|
1320
1244
|
return this.get(
|
|
@@ -1322,11 +1246,12 @@ export default class Inibase {
|
|
|
1322
1246
|
Utils.isArrayOfObjects(RETURN)
|
|
1323
1247
|
? RETURN.map((data: Data) => data.id)
|
|
1324
1248
|
: ((RETURN as Data).id as number),
|
|
1325
|
-
options
|
|
1249
|
+
options,
|
|
1250
|
+
!Utils.isArrayOfObjects(data) // return only one item if data is not array of objects
|
|
1326
1251
|
);
|
|
1327
1252
|
}
|
|
1328
1253
|
|
|
1329
|
-
public async put(
|
|
1254
|
+
public async put<returnPostedDataType extends boolean = true>(
|
|
1330
1255
|
tableName: string,
|
|
1331
1256
|
data: Data | Data[],
|
|
1332
1257
|
where?: number | string | (number | string)[] | Criteria,
|
|
@@ -1334,8 +1259,10 @@ export default class Inibase {
|
|
|
1334
1259
|
page: 1,
|
|
1335
1260
|
per_page: 15,
|
|
1336
1261
|
},
|
|
1337
|
-
returnPostedData
|
|
1338
|
-
): Promise<
|
|
1262
|
+
returnPostedData?: returnPostedDataType
|
|
1263
|
+
): Promise<
|
|
1264
|
+
(returnPostedDataType extends true ? Data | Data[] : void) | null
|
|
1265
|
+
> {
|
|
1339
1266
|
const schema = await this.getTableSchema(tableName);
|
|
1340
1267
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1341
1268
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
@@ -1345,15 +1272,15 @@ export default class Inibase {
|
|
|
1345
1272
|
if (!where) {
|
|
1346
1273
|
if (Utils.isArrayOfObjects(data)) {
|
|
1347
1274
|
if (
|
|
1348
|
-
!
|
|
1349
|
-
(item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)
|
|
1275
|
+
!data.every(
|
|
1276
|
+
(item: any) => item.hasOwnProperty("id") && Utils.isValidID(item.id)
|
|
1350
1277
|
)
|
|
1351
1278
|
)
|
|
1352
1279
|
throw this.throwError("INVALID_ID");
|
|
1353
1280
|
return this.put(
|
|
1354
1281
|
tableName,
|
|
1355
1282
|
data,
|
|
1356
|
-
|
|
1283
|
+
data.map((item: { id: any }) => item.id)
|
|
1357
1284
|
);
|
|
1358
1285
|
} else if (data.hasOwnProperty("id")) {
|
|
1359
1286
|
if (!Utils.isValidID((data as Data).id))
|
|
@@ -1361,72 +1288,90 @@ export default class Inibase {
|
|
|
1361
1288
|
return this.put(
|
|
1362
1289
|
tableName,
|
|
1363
1290
|
data,
|
|
1364
|
-
|
|
1291
|
+
Utils.decodeID((data as Data).id as string, this.salt)
|
|
1365
1292
|
);
|
|
1366
1293
|
} else {
|
|
1367
1294
|
const pathesContents = this.joinPathesContents(
|
|
1368
1295
|
join(this.folder, this.database, tableName),
|
|
1369
1296
|
Utils.isArrayOfObjects(data)
|
|
1370
|
-
?
|
|
1297
|
+
? data.map((item: any) => ({
|
|
1371
1298
|
...(({ id, ...restOfData }) => restOfData)(item),
|
|
1372
|
-
|
|
1299
|
+
updatedAt: new Date(),
|
|
1373
1300
|
}))
|
|
1374
1301
|
: {
|
|
1375
1302
|
...(({ id, ...restOfData }) => restOfData)(data as Data),
|
|
1376
|
-
|
|
1303
|
+
updatedAt: new Date(),
|
|
1377
1304
|
}
|
|
1378
1305
|
);
|
|
1379
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1306
|
+
for await (const [path, content] of Object.entries(pathesContents))
|
|
1380
1307
|
await File.replace(path, content);
|
|
1381
|
-
|
|
1308
|
+
|
|
1309
|
+
if (returnPostedData) return this.get(tableName, where, options) as any;
|
|
1382
1310
|
}
|
|
1383
|
-
} else if (
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1311
|
+
} else if (
|
|
1312
|
+
(Array.isArray(where) &&
|
|
1313
|
+
(where.every(Utils.isValidID) || where.every(Utils.isNumber))) ||
|
|
1314
|
+
Utils.isValidID(where) ||
|
|
1315
|
+
Utils.isNumber(where)
|
|
1316
|
+
) {
|
|
1317
|
+
if (
|
|
1318
|
+
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
1319
|
+
Utils.isValidID(where)
|
|
1320
|
+
) {
|
|
1321
|
+
const lineNumbers = await this.get(
|
|
1322
|
+
tableName,
|
|
1323
|
+
where,
|
|
1324
|
+
undefined,
|
|
1325
|
+
undefined,
|
|
1326
|
+
true
|
|
1327
|
+
);
|
|
1328
|
+
return this.put(tableName, data, lineNumbers);
|
|
1329
|
+
} else if (
|
|
1330
|
+
(Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1331
|
+
Utils.isNumber(where)
|
|
1332
|
+
) {
|
|
1333
|
+
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1334
|
+
const pathesContents = Object.fromEntries(
|
|
1335
|
+
Object.entries(
|
|
1336
|
+
this.joinPathesContents(
|
|
1337
|
+
join(this.folder, this.database, tableName),
|
|
1338
|
+
Utils.isArrayOfObjects(data)
|
|
1339
|
+
? data.map((item: any) => ({
|
|
1340
|
+
...item,
|
|
1341
|
+
updatedAt: new Date(),
|
|
1342
|
+
}))
|
|
1343
|
+
: { ...data, updatedAt: new Date() }
|
|
1344
|
+
)
|
|
1345
|
+
).map(([key, value]) => [
|
|
1346
|
+
key,
|
|
1347
|
+
([...(Array.isArray(where) ? where : [where])] as number[]).reduce(
|
|
1348
|
+
(obj, key, index) => ({
|
|
1349
|
+
...obj,
|
|
1350
|
+
[key]: Array.isArray(value) ? value[index] : value,
|
|
1351
|
+
}),
|
|
1352
|
+
{}
|
|
1353
|
+
),
|
|
1354
|
+
])
|
|
1355
|
+
);
|
|
1356
|
+
for await (const [path, content] of Object.entries(pathesContents))
|
|
1357
|
+
await File.replace(path, content);
|
|
1358
|
+
|
|
1359
|
+
if (returnPostedData)
|
|
1360
|
+
return this.get(
|
|
1361
|
+
tableName,
|
|
1362
|
+
where,
|
|
1363
|
+
options,
|
|
1364
|
+
!Array.isArray(where)
|
|
1365
|
+
) as any;
|
|
1366
|
+
}
|
|
1367
|
+
} else if (typeof where === "object") {
|
|
1368
|
+
const lineNumbers = this.get(
|
|
1369
|
+
tableName,
|
|
1370
|
+
where,
|
|
1390
1371
|
undefined,
|
|
1391
|
-
"number",
|
|
1392
1372
|
undefined,
|
|
1393
|
-
|
|
1394
|
-
0,
|
|
1395
|
-
false,
|
|
1396
|
-
this.salt
|
|
1397
|
-
);
|
|
1398
|
-
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1399
|
-
throw this.throwError("INVALID_ID");
|
|
1400
|
-
return this.put(tableName, data, Object.keys(lineNumbers).map(Number));
|
|
1401
|
-
} else if (Utils.isNumber(where)) {
|
|
1402
|
-
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1403
|
-
const pathesContents = Object.fromEntries(
|
|
1404
|
-
Object.entries(
|
|
1405
|
-
this.joinPathesContents(
|
|
1406
|
-
join(this.folder, this.database, tableName),
|
|
1407
|
-
Utils.isArrayOfObjects(data)
|
|
1408
|
-
? (data as Data[]).map((item) => ({
|
|
1409
|
-
...item,
|
|
1410
|
-
updated_at: new Date(),
|
|
1411
|
-
}))
|
|
1412
|
-
: { ...data, updated_at: new Date() }
|
|
1413
|
-
)
|
|
1414
|
-
).map(([key, value]) => [
|
|
1415
|
-
key,
|
|
1416
|
-
([...(Array.isArray(where) ? where : [where])] as number[]).reduce(
|
|
1417
|
-
(obj, key, index) => ({
|
|
1418
|
-
...obj,
|
|
1419
|
-
[key]: Array.isArray(value) ? value[index] : value,
|
|
1420
|
-
}),
|
|
1421
|
-
{}
|
|
1422
|
-
),
|
|
1423
|
-
])
|
|
1373
|
+
true
|
|
1424
1374
|
);
|
|
1425
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1426
|
-
await File.replace(path, content);
|
|
1427
|
-
if (returnPostedData) return this.get(tableName, where, options);
|
|
1428
|
-
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1429
|
-
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1430
1375
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1431
1376
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1432
1377
|
return this.put(tableName, data, lineNumbers);
|
|
@@ -1447,64 +1392,196 @@ export default class Inibase {
|
|
|
1447
1392
|
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1448
1393
|
if (files.length) {
|
|
1449
1394
|
for (const file in files.filter(
|
|
1450
|
-
(fileName: string) => fileName !== "schema"
|
|
1395
|
+
(fileName: string) => fileName !== "schema.json"
|
|
1451
1396
|
))
|
|
1452
1397
|
await unlink(join(this.folder, this.database, tableName, file));
|
|
1453
1398
|
}
|
|
1454
1399
|
return "*";
|
|
1455
|
-
} else if (
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1400
|
+
} else if (
|
|
1401
|
+
(Array.isArray(where) &&
|
|
1402
|
+
(where.every(Utils.isValidID) || where.every(Utils.isNumber))) ||
|
|
1403
|
+
Utils.isValidID(where) ||
|
|
1404
|
+
Utils.isNumber(where)
|
|
1405
|
+
) {
|
|
1406
|
+
if (
|
|
1407
|
+
(Array.isArray(where) && where.every(Utils.isValidID)) ||
|
|
1408
|
+
Utils.isValidID(where)
|
|
1409
|
+
) {
|
|
1410
|
+
const lineNumbers = await this.get(
|
|
1411
|
+
tableName,
|
|
1412
|
+
where,
|
|
1413
|
+
undefined,
|
|
1414
|
+
undefined,
|
|
1415
|
+
true
|
|
1416
|
+
);
|
|
1417
|
+
return this.delete(tableName, lineNumbers, where as string | string[]);
|
|
1418
|
+
} else if (
|
|
1419
|
+
(Array.isArray(where) && where.every(Utils.isNumber)) ||
|
|
1420
|
+
Utils.isNumber(where)
|
|
1421
|
+
) {
|
|
1422
|
+
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1423
|
+
const files = await readdir(
|
|
1424
|
+
join(this.folder, this.database, tableName)
|
|
1425
|
+
);
|
|
1426
|
+
if (files.length) {
|
|
1427
|
+
if (!_id)
|
|
1428
|
+
_id = Object.values(
|
|
1429
|
+
(
|
|
1430
|
+
await File.get(
|
|
1431
|
+
join(this.folder, this.database, tableName, "id.inib"),
|
|
1432
|
+
where,
|
|
1433
|
+
"number",
|
|
1434
|
+
undefined,
|
|
1435
|
+
this.salt
|
|
1436
|
+
)
|
|
1437
|
+
)[0]
|
|
1438
|
+
).map((id) => Utils.encodeID(Number(id), this.salt));
|
|
1439
|
+
for (const file of files.filter((fileName: string) =>
|
|
1440
|
+
fileName.endsWith(".inib")
|
|
1441
|
+
))
|
|
1442
|
+
await File.remove(
|
|
1443
|
+
join(this.folder, this.database, tableName, file),
|
|
1444
|
+
where as number | number[]
|
|
1445
|
+
);
|
|
1446
|
+
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1450
|
+
const lineNumbers = this.get(
|
|
1451
|
+
tableName,
|
|
1452
|
+
where,
|
|
1462
1453
|
undefined,
|
|
1463
|
-
"number",
|
|
1464
1454
|
undefined,
|
|
1465
|
-
|
|
1466
|
-
0,
|
|
1467
|
-
false,
|
|
1468
|
-
this.salt
|
|
1455
|
+
true
|
|
1469
1456
|
);
|
|
1470
|
-
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1471
|
-
throw this.throwError("INVALID_ID");
|
|
1472
|
-
return this.delete(
|
|
1473
|
-
tableName,
|
|
1474
|
-
Object.keys(lineNumbers).map(Number),
|
|
1475
|
-
where as string | string[]
|
|
1476
|
-
);
|
|
1477
|
-
} else if (Utils.isNumber(where)) {
|
|
1478
|
-
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1479
|
-
if (files.length) {
|
|
1480
|
-
if (!_id)
|
|
1481
|
-
_id = Object.values(
|
|
1482
|
-
(
|
|
1483
|
-
await File.get(
|
|
1484
|
-
join(this.folder, this.database, tableName, "id.inib"),
|
|
1485
|
-
where as number | number[],
|
|
1486
|
-
"number",
|
|
1487
|
-
undefined,
|
|
1488
|
-
this.salt
|
|
1489
|
-
)
|
|
1490
|
-
)[0]
|
|
1491
|
-
).map((id) => UtilsServer.encodeID(Number(id), this.salt));
|
|
1492
|
-
for (const file of files.filter(
|
|
1493
|
-
(fileName: string) =>
|
|
1494
|
-
fileName.endsWith(".inib") && fileName !== "schema"
|
|
1495
|
-
))
|
|
1496
|
-
await File.remove(
|
|
1497
|
-
join(this.folder, this.database, tableName, file),
|
|
1498
|
-
where as number | number[]
|
|
1499
|
-
);
|
|
1500
|
-
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1501
|
-
}
|
|
1502
|
-
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1503
|
-
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1504
1457
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1505
1458
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1506
1459
|
return this.delete(tableName, lineNumbers);
|
|
1507
1460
|
} else throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
1508
1461
|
return null;
|
|
1509
1462
|
}
|
|
1463
|
+
|
|
1464
|
+
public async sum(
|
|
1465
|
+
tableName: string,
|
|
1466
|
+
columns: string,
|
|
1467
|
+
where?: number | string | (number | string)[] | Criteria
|
|
1468
|
+
): Promise<number>;
|
|
1469
|
+
public async sum(
|
|
1470
|
+
tableName: string,
|
|
1471
|
+
columns: string[],
|
|
1472
|
+
where?: number | string | (number | string)[] | Criteria
|
|
1473
|
+
): Promise<Record<string, number>>;
|
|
1474
|
+
public async sum(
|
|
1475
|
+
tableName: string,
|
|
1476
|
+
columns: string | string[],
|
|
1477
|
+
where?: number | string | (number | string)[] | Criteria
|
|
1478
|
+
): Promise<number | Record<string, number>> {
|
|
1479
|
+
let RETURN: Record<string, number>;
|
|
1480
|
+
const schema = await this.getTableSchema(tableName);
|
|
1481
|
+
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1482
|
+
if (
|
|
1483
|
+
!(await File.isExists(
|
|
1484
|
+
join(this.folder, this.database, tableName, "id.inib")
|
|
1485
|
+
))
|
|
1486
|
+
)
|
|
1487
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1488
|
+
if (!Array.isArray(columns)) columns = [columns];
|
|
1489
|
+
for await (const column of columns) {
|
|
1490
|
+
const columnPath = join(
|
|
1491
|
+
this.folder,
|
|
1492
|
+
this.database,
|
|
1493
|
+
tableName,
|
|
1494
|
+
column + ".inib"
|
|
1495
|
+
);
|
|
1496
|
+
if (await File.isExists(columnPath)) {
|
|
1497
|
+
if (where) {
|
|
1498
|
+
const lineNumbers = await this.get(
|
|
1499
|
+
tableName,
|
|
1500
|
+
where,
|
|
1501
|
+
undefined,
|
|
1502
|
+
undefined,
|
|
1503
|
+
true
|
|
1504
|
+
);
|
|
1505
|
+
RETURN[column] = await File.sum(columnPath, lineNumbers);
|
|
1506
|
+
} else RETURN[column] = await File.sum(columnPath);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return Array.isArray(columns) ? RETURN : Object.values(RETURN)[0];
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
public async max(
|
|
1513
|
+
tableName: string,
|
|
1514
|
+
columns: string | string[],
|
|
1515
|
+
where?: number | string | (number | string)[] | Criteria
|
|
1516
|
+
) {
|
|
1517
|
+
let RETURN: Record<string, number>;
|
|
1518
|
+
const schema = await this.getTableSchema(tableName);
|
|
1519
|
+
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1520
|
+
if (
|
|
1521
|
+
!(await File.isExists(
|
|
1522
|
+
join(this.folder, this.database, tableName, "id.inib")
|
|
1523
|
+
))
|
|
1524
|
+
)
|
|
1525
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1526
|
+
if (!Array.isArray(columns)) columns = [columns];
|
|
1527
|
+
for await (const column of columns) {
|
|
1528
|
+
const columnPath = join(
|
|
1529
|
+
this.folder,
|
|
1530
|
+
this.database,
|
|
1531
|
+
tableName,
|
|
1532
|
+
column + ".inib"
|
|
1533
|
+
);
|
|
1534
|
+
if (await File.isExists(columnPath)) {
|
|
1535
|
+
if (where) {
|
|
1536
|
+
const lineNumbers = await this.get(
|
|
1537
|
+
tableName,
|
|
1538
|
+
where,
|
|
1539
|
+
undefined,
|
|
1540
|
+
undefined,
|
|
1541
|
+
true
|
|
1542
|
+
);
|
|
1543
|
+
RETURN[column] = await File.max(columnPath, lineNumbers);
|
|
1544
|
+
} else RETURN[column] = await File.max(columnPath);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return RETURN;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
public async min(
|
|
1551
|
+
tableName: string,
|
|
1552
|
+
columns: string | string[],
|
|
1553
|
+
where?: number | string | (number | string)[] | Criteria
|
|
1554
|
+
) {
|
|
1555
|
+
let RETURN: Record<string, number>;
|
|
1556
|
+
const schema = await this.getTableSchema(tableName);
|
|
1557
|
+
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1558
|
+
if (
|
|
1559
|
+
!(await File.isExists(
|
|
1560
|
+
join(this.folder, this.database, tableName, "id.inib")
|
|
1561
|
+
))
|
|
1562
|
+
)
|
|
1563
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1564
|
+
if (!Array.isArray(columns)) columns = [columns];
|
|
1565
|
+
for await (const column of columns) {
|
|
1566
|
+
const columnPath = join(
|
|
1567
|
+
this.folder,
|
|
1568
|
+
this.database,
|
|
1569
|
+
tableName,
|
|
1570
|
+
column + ".inib"
|
|
1571
|
+
);
|
|
1572
|
+
if (await File.isExists(columnPath)) {
|
|
1573
|
+
if (where) {
|
|
1574
|
+
const lineNumbers = await this.get(
|
|
1575
|
+
tableName,
|
|
1576
|
+
where,
|
|
1577
|
+
undefined,
|
|
1578
|
+
undefined,
|
|
1579
|
+
true
|
|
1580
|
+
);
|
|
1581
|
+
RETURN[column] = await File.min(columnPath, lineNumbers);
|
|
1582
|
+
} else RETURN[column] = await File.min(columnPath);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
return RETURN;
|
|
1586
|
+
}
|
|
1510
1587
|
}
|