inibase 1.0.0-rc.10 → 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 +246 -73
- package/index.test.ts +45 -3
- package/index.ts +442 -349
- 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,33 +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
|
-
} 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
|
|
619
543
|
RETURN[(prefix ?? "") + key] = File.encode(value) as
|
|
620
544
|
| boolean
|
|
621
545
|
| number
|
|
@@ -635,15 +559,18 @@ export default class Inibase {
|
|
|
635
559
|
return addPathToKeys(CombineData(data), mainPath);
|
|
636
560
|
}
|
|
637
561
|
|
|
638
|
-
public async get(
|
|
562
|
+
public async get<O extends boolean = false, N extends boolean = false>(
|
|
639
563
|
tableName: string,
|
|
640
564
|
where?: string | number | (string | number)[] | Criteria,
|
|
641
565
|
options: Options = {
|
|
642
566
|
page: 1,
|
|
643
567
|
per_page: 15,
|
|
644
568
|
},
|
|
645
|
-
|
|
646
|
-
|
|
569
|
+
onlyOne?: O,
|
|
570
|
+
onlyLinesNumbers?: N
|
|
571
|
+
): Promise<
|
|
572
|
+
(N extends true ? number[] : O extends true ? Data : Data[]) | null
|
|
573
|
+
> {
|
|
647
574
|
if (!options.columns) options.columns = [];
|
|
648
575
|
else if (!Array.isArray(options.columns))
|
|
649
576
|
options.columns = [options.columns];
|
|
@@ -762,19 +689,21 @@ export default class Inibase {
|
|
|
762
689
|
if (!RETURN[index][field.key][_i][child_field.key])
|
|
763
690
|
RETURN[index][field.key][_i][child_field.key] =
|
|
764
691
|
[];
|
|
765
|
-
value[_i].forEach(
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
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
|
+
] = {};
|
|
771
702
|
RETURN[index][field.key][_i][child_field.key][
|
|
772
703
|
_index
|
|
773
|
-
] =
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
][key] = _element;
|
|
777
|
-
});
|
|
704
|
+
][key] = _element;
|
|
705
|
+
}
|
|
706
|
+
);
|
|
778
707
|
}
|
|
779
708
|
}
|
|
780
709
|
);
|
|
@@ -793,6 +722,7 @@ export default class Inibase {
|
|
|
793
722
|
!Utils.isArrayOfObjects(children.children)
|
|
794
723
|
);
|
|
795
724
|
}
|
|
725
|
+
|
|
796
726
|
Object.entries(
|
|
797
727
|
(await getItemsFromSchema(
|
|
798
728
|
path,
|
|
@@ -808,7 +738,10 @@ export default class Inibase {
|
|
|
808
738
|
if (RETURN[index][field.key])
|
|
809
739
|
Object.entries(item).forEach(([key, value], _index) => {
|
|
810
740
|
RETURN[index][field.key] = RETURN[index][field.key].map(
|
|
811
|
-
(_obj, _i) => ({
|
|
741
|
+
(_obj: any, _i: string | number) => ({
|
|
742
|
+
..._obj,
|
|
743
|
+
[key]: value[_i],
|
|
744
|
+
})
|
|
812
745
|
);
|
|
813
746
|
});
|
|
814
747
|
else if (Object.values(item).every(Utils.isArrayOfArrays))
|
|
@@ -960,15 +893,20 @@ export default class Inibase {
|
|
|
960
893
|
)
|
|
961
894
|
)
|
|
962
895
|
);
|
|
963
|
-
} 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
|
+
) {
|
|
964
902
|
let Ids = where as string | number | (string | number)[];
|
|
965
903
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
966
904
|
const [lineNumbers, countItems] = await File.search(
|
|
967
905
|
idFilePath,
|
|
968
906
|
"[]",
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
907
|
+
Ids.map((id) =>
|
|
908
|
+
Utils.isNumber(id) ? Number(id) : Utils.decodeID(id, this.salt)
|
|
909
|
+
),
|
|
972
910
|
undefined,
|
|
973
911
|
"number",
|
|
974
912
|
undefined,
|
|
@@ -982,6 +920,9 @@ export default class Inibase {
|
|
|
982
920
|
"INVALID_ID",
|
|
983
921
|
where as number | string | (number | string)[]
|
|
984
922
|
);
|
|
923
|
+
|
|
924
|
+
if (onlyLinesNumbers) return Object.keys(lineNumbers).map(Number) as any;
|
|
925
|
+
|
|
985
926
|
RETURN = Object.values(
|
|
986
927
|
(await getItemsFromSchema(
|
|
987
928
|
join(this.folder, this.database, tableName),
|
|
@@ -1215,20 +1156,20 @@ export default class Inibase {
|
|
|
1215
1156
|
|
|
1216
1157
|
RETURN = await applyCriteria(where as Criteria);
|
|
1217
1158
|
if (RETURN) {
|
|
1218
|
-
if (onlyLinesNumbers) return Object.keys(RETURN).map(Number);
|
|
1159
|
+
if (onlyLinesNumbers) return Object.keys(RETURN).map(Number) as any;
|
|
1219
1160
|
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]).map(
|
|
1220
1161
|
(key) => parse(key).name
|
|
1221
1162
|
);
|
|
1222
1163
|
RETURN = Object.values(
|
|
1223
1164
|
Utils.deepMerge(
|
|
1165
|
+
RETURN,
|
|
1224
1166
|
await getItemsFromSchema(
|
|
1225
1167
|
join(this.folder, this.database, tableName),
|
|
1226
1168
|
schema.filter(
|
|
1227
1169
|
(field) => !alreadyExistsColumns.includes(field.key)
|
|
1228
1170
|
),
|
|
1229
1171
|
Object.keys(RETURN).map(Number)
|
|
1230
|
-
)
|
|
1231
|
-
RETURN
|
|
1172
|
+
)
|
|
1232
1173
|
)
|
|
1233
1174
|
);
|
|
1234
1175
|
}
|
|
@@ -1250,55 +1191,54 @@ export default class Inibase {
|
|
|
1250
1191
|
total_pages: Math.ceil(greatestTotalItems / options.per_page),
|
|
1251
1192
|
total: greatestTotalItems,
|
|
1252
1193
|
};
|
|
1253
|
-
return RETURN;
|
|
1194
|
+
return onlyOne ? RETURN[0] : RETURN;
|
|
1254
1195
|
}
|
|
1255
1196
|
|
|
1256
|
-
public async post(
|
|
1197
|
+
public async post<DataType extends Data | Data[]>(
|
|
1257
1198
|
tableName: string,
|
|
1258
|
-
data:
|
|
1199
|
+
data: DataType,
|
|
1259
1200
|
options: Options = {
|
|
1260
1201
|
page: 1,
|
|
1261
1202
|
per_page: 15,
|
|
1262
1203
|
},
|
|
1263
1204
|
returnPostedData: boolean = true
|
|
1264
|
-
): Promise<
|
|
1205
|
+
): Promise<
|
|
1206
|
+
DataType extends Data ? Data | null | void : Data[] | null | void
|
|
1207
|
+
> {
|
|
1265
1208
|
const schema = await this.getTableSchema(tableName);
|
|
1266
1209
|
let RETURN: Data | Data[] | null | undefined;
|
|
1267
1210
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1268
1211
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
: 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];
|
|
1276
1218
|
if (Utils.isArrayOfObjects(data))
|
|
1277
|
-
|
|
1219
|
+
data.forEach((single_data: any, index: string | number) => {
|
|
1278
1220
|
if (!RETURN) RETURN = [];
|
|
1279
|
-
RETURN[index] = (({ id,
|
|
1221
|
+
RETURN[index] = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
1280
1222
|
id: ++last_id,
|
|
1281
1223
|
...rest,
|
|
1282
|
-
|
|
1224
|
+
createdAt: new Date(),
|
|
1283
1225
|
}))(single_data);
|
|
1284
1226
|
});
|
|
1285
1227
|
else
|
|
1286
|
-
RETURN = (({ id,
|
|
1228
|
+
RETURN = (({ id, updatedAt, createdAt, ...rest }) => ({
|
|
1287
1229
|
id: ++last_id,
|
|
1288
1230
|
...rest,
|
|
1289
|
-
|
|
1231
|
+
createdAt: new Date(),
|
|
1290
1232
|
}))(data as Data);
|
|
1291
1233
|
if (!RETURN) throw this.throwError("NO_DATA");
|
|
1234
|
+
|
|
1292
1235
|
RETURN = this.formatData(RETURN, schema);
|
|
1293
1236
|
const pathesContents = this.joinPathesContents(
|
|
1294
1237
|
join(this.folder, this.database, tableName),
|
|
1295
1238
|
RETURN
|
|
1296
1239
|
);
|
|
1297
1240
|
for await (const [path, content] of Object.entries(pathesContents))
|
|
1298
|
-
await
|
|
1299
|
-
path,
|
|
1300
|
-
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1301
|
-
);
|
|
1241
|
+
await File.replace(path, { [last_line_number]: content });
|
|
1302
1242
|
|
|
1303
1243
|
if (returnPostedData)
|
|
1304
1244
|
return this.get(
|
|
@@ -1306,11 +1246,12 @@ export default class Inibase {
|
|
|
1306
1246
|
Utils.isArrayOfObjects(RETURN)
|
|
1307
1247
|
? RETURN.map((data: Data) => data.id)
|
|
1308
1248
|
: ((RETURN as Data).id as number),
|
|
1309
|
-
options
|
|
1249
|
+
options,
|
|
1250
|
+
!Utils.isArrayOfObjects(data) // return only one item if data is not array of objects
|
|
1310
1251
|
);
|
|
1311
1252
|
}
|
|
1312
1253
|
|
|
1313
|
-
public async put(
|
|
1254
|
+
public async put<returnPostedDataType extends boolean = true>(
|
|
1314
1255
|
tableName: string,
|
|
1315
1256
|
data: Data | Data[],
|
|
1316
1257
|
where?: number | string | (number | string)[] | Criteria,
|
|
@@ -1318,8 +1259,10 @@ export default class Inibase {
|
|
|
1318
1259
|
page: 1,
|
|
1319
1260
|
per_page: 15,
|
|
1320
1261
|
},
|
|
1321
|
-
returnPostedData
|
|
1322
|
-
): Promise<
|
|
1262
|
+
returnPostedData?: returnPostedDataType
|
|
1263
|
+
): Promise<
|
|
1264
|
+
(returnPostedDataType extends true ? Data | Data[] : void) | null
|
|
1265
|
+
> {
|
|
1323
1266
|
const schema = await this.getTableSchema(tableName);
|
|
1324
1267
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1325
1268
|
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
@@ -1329,15 +1272,15 @@ export default class Inibase {
|
|
|
1329
1272
|
if (!where) {
|
|
1330
1273
|
if (Utils.isArrayOfObjects(data)) {
|
|
1331
1274
|
if (
|
|
1332
|
-
!
|
|
1333
|
-
(item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)
|
|
1275
|
+
!data.every(
|
|
1276
|
+
(item: any) => item.hasOwnProperty("id") && Utils.isValidID(item.id)
|
|
1334
1277
|
)
|
|
1335
1278
|
)
|
|
1336
1279
|
throw this.throwError("INVALID_ID");
|
|
1337
1280
|
return this.put(
|
|
1338
1281
|
tableName,
|
|
1339
1282
|
data,
|
|
1340
|
-
|
|
1283
|
+
data.map((item: { id: any }) => item.id)
|
|
1341
1284
|
);
|
|
1342
1285
|
} else if (data.hasOwnProperty("id")) {
|
|
1343
1286
|
if (!Utils.isValidID((data as Data).id))
|
|
@@ -1345,72 +1288,90 @@ export default class Inibase {
|
|
|
1345
1288
|
return this.put(
|
|
1346
1289
|
tableName,
|
|
1347
1290
|
data,
|
|
1348
|
-
|
|
1291
|
+
Utils.decodeID((data as Data).id as string, this.salt)
|
|
1349
1292
|
);
|
|
1350
1293
|
} else {
|
|
1351
1294
|
const pathesContents = this.joinPathesContents(
|
|
1352
1295
|
join(this.folder, this.database, tableName),
|
|
1353
1296
|
Utils.isArrayOfObjects(data)
|
|
1354
|
-
?
|
|
1297
|
+
? data.map((item: any) => ({
|
|
1355
1298
|
...(({ id, ...restOfData }) => restOfData)(item),
|
|
1356
|
-
|
|
1299
|
+
updatedAt: new Date(),
|
|
1357
1300
|
}))
|
|
1358
1301
|
: {
|
|
1359
1302
|
...(({ id, ...restOfData }) => restOfData)(data as Data),
|
|
1360
|
-
|
|
1303
|
+
updatedAt: new Date(),
|
|
1361
1304
|
}
|
|
1362
1305
|
);
|
|
1363
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1306
|
+
for await (const [path, content] of Object.entries(pathesContents))
|
|
1364
1307
|
await File.replace(path, content);
|
|
1365
|
-
|
|
1308
|
+
|
|
1309
|
+
if (returnPostedData) return this.get(tableName, where, options) as any;
|
|
1366
1310
|
}
|
|
1367
|
-
} else if (
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
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,
|
|
1374
1371
|
undefined,
|
|
1375
|
-
"number",
|
|
1376
1372
|
undefined,
|
|
1377
|
-
|
|
1378
|
-
0,
|
|
1379
|
-
false,
|
|
1380
|
-
this.salt
|
|
1381
|
-
);
|
|
1382
|
-
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1383
|
-
throw this.throwError("INVALID_ID");
|
|
1384
|
-
return this.put(tableName, data, Object.keys(lineNumbers).map(Number));
|
|
1385
|
-
} else if (Utils.isNumber(where)) {
|
|
1386
|
-
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1387
|
-
const pathesContents = Object.fromEntries(
|
|
1388
|
-
Object.entries(
|
|
1389
|
-
this.joinPathesContents(
|
|
1390
|
-
join(this.folder, this.database, tableName),
|
|
1391
|
-
Utils.isArrayOfObjects(data)
|
|
1392
|
-
? (data as Data[]).map((item) => ({
|
|
1393
|
-
...item,
|
|
1394
|
-
updated_at: new Date(),
|
|
1395
|
-
}))
|
|
1396
|
-
: { ...data, updated_at: new Date() }
|
|
1397
|
-
)
|
|
1398
|
-
).map(([key, value]) => [
|
|
1399
|
-
key,
|
|
1400
|
-
([...(Array.isArray(where) ? where : [where])] as number[]).reduce(
|
|
1401
|
-
(obj, key, index) => ({
|
|
1402
|
-
...obj,
|
|
1403
|
-
[key]: Array.isArray(value) ? value[index] : value,
|
|
1404
|
-
}),
|
|
1405
|
-
{}
|
|
1406
|
-
),
|
|
1407
|
-
])
|
|
1373
|
+
true
|
|
1408
1374
|
);
|
|
1409
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1410
|
-
await File.replace(path, content);
|
|
1411
|
-
if (returnPostedData) return this.get(tableName, where, options);
|
|
1412
|
-
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1413
|
-
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1414
1375
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1415
1376
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1416
1377
|
return this.put(tableName, data, lineNumbers);
|
|
@@ -1431,64 +1392,196 @@ export default class Inibase {
|
|
|
1431
1392
|
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1432
1393
|
if (files.length) {
|
|
1433
1394
|
for (const file in files.filter(
|
|
1434
|
-
(fileName: string) => fileName !== "schema"
|
|
1395
|
+
(fileName: string) => fileName !== "schema.json"
|
|
1435
1396
|
))
|
|
1436
1397
|
await unlink(join(this.folder, this.database, tableName, file));
|
|
1437
1398
|
}
|
|
1438
1399
|
return "*";
|
|
1439
|
-
} else if (
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
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,
|
|
1446
1453
|
undefined,
|
|
1447
|
-
"number",
|
|
1448
1454
|
undefined,
|
|
1449
|
-
|
|
1450
|
-
0,
|
|
1451
|
-
false,
|
|
1452
|
-
this.salt
|
|
1453
|
-
);
|
|
1454
|
-
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1455
|
-
throw this.throwError("INVALID_ID");
|
|
1456
|
-
return this.delete(
|
|
1457
|
-
tableName,
|
|
1458
|
-
Object.keys(lineNumbers).map(Number),
|
|
1459
|
-
where as string | string[]
|
|
1455
|
+
true
|
|
1460
1456
|
);
|
|
1461
|
-
} else if (Utils.isNumber(where)) {
|
|
1462
|
-
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1463
|
-
if (files.length) {
|
|
1464
|
-
if (!_id)
|
|
1465
|
-
_id = Object.values(
|
|
1466
|
-
await File.get(
|
|
1467
|
-
join(this.folder, this.database, tableName, "id.inib"),
|
|
1468
|
-
where as number | number[],
|
|
1469
|
-
"number",
|
|
1470
|
-
undefined,
|
|
1471
|
-
this.salt
|
|
1472
|
-
)
|
|
1473
|
-
)
|
|
1474
|
-
.map(Number)
|
|
1475
|
-
.map((id) => UtilsServer.encodeID(id, this.salt));
|
|
1476
|
-
for (const file of files.filter(
|
|
1477
|
-
(fileName: string) =>
|
|
1478
|
-
fileName.endsWith(".inib") && fileName !== "schema"
|
|
1479
|
-
))
|
|
1480
|
-
await File.remove(
|
|
1481
|
-
join(this.folder, this.database, tableName, file),
|
|
1482
|
-
where as number | number[]
|
|
1483
|
-
);
|
|
1484
|
-
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1485
|
-
}
|
|
1486
|
-
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1487
|
-
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1488
1457
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1489
1458
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1490
1459
|
return this.delete(tableName, lineNumbers);
|
|
1491
1460
|
} else throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
1492
1461
|
return null;
|
|
1493
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
|
+
}
|
|
1494
1587
|
}
|