inibase 1.0.0-rc.0 → 1.0.0-rc.11
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 +45 -62
- package/file.ts +325 -103
- package/index.test.ts +247 -0
- package/index.ts +893 -627
- package/package.json +7 -6
- package/tsconfig.json +2 -1
- package/utils.server.ts +79 -0
- package/utils.ts +166 -64
package/index.ts
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "
|
|
11
|
-
import {
|
|
12
|
-
import { createDecipheriv, createCipheriv, scryptSync } from "crypto";
|
|
13
|
-
import Utils from "./utils";
|
|
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";
|
|
11
|
+
import { scryptSync } from "node:crypto";
|
|
14
12
|
import File from "./file";
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
import Utils from "./utils";
|
|
14
|
+
import UtilsServer from "./utils.server";
|
|
17
15
|
|
|
18
16
|
export type Data = {
|
|
19
17
|
id?: number | string;
|
|
20
18
|
[key: string]: any;
|
|
21
|
-
[id: number]: any;
|
|
22
19
|
created_at?: Date;
|
|
23
20
|
updated_at?: Date;
|
|
24
21
|
};
|
|
@@ -32,36 +29,51 @@ export type FieldType =
|
|
|
32
29
|
| "url"
|
|
33
30
|
| "table"
|
|
34
31
|
| "object"
|
|
32
|
+
| "array"
|
|
35
33
|
| "password"
|
|
36
|
-
| "
|
|
37
|
-
|
|
38
|
-
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
34
|
+
| "html"
|
|
35
|
+
| "ip"
|
|
36
|
+
| "id";
|
|
37
|
+
type FieldDefault = {
|
|
38
|
+
id?: string | number | null | undefined;
|
|
39
|
+
key: string;
|
|
40
|
+
required?: boolean;
|
|
41
|
+
children?: any;
|
|
42
|
+
};
|
|
43
|
+
type FieldStringType = {
|
|
44
|
+
type: Exclude<FieldType, "array" | "object">;
|
|
45
|
+
};
|
|
46
|
+
type FieldStringArrayType = {
|
|
47
|
+
type: Exclude<FieldType, "array" | "object">[];
|
|
48
|
+
};
|
|
49
|
+
type FieldArrayType = {
|
|
50
|
+
type: "array";
|
|
51
|
+
children: FieldType | FieldType[] | Schema;
|
|
52
|
+
};
|
|
53
|
+
type FieldArrayArrayType = {
|
|
54
|
+
type: ["array", ...FieldType[]];
|
|
55
|
+
children: FieldType | FieldType[];
|
|
56
|
+
};
|
|
57
|
+
type FieldObjectType = {
|
|
58
|
+
type: "object";
|
|
59
|
+
children: Schema;
|
|
60
|
+
};
|
|
61
|
+
// if "type" is array, make "array" at first place, and "number" & "string" at last place of the array
|
|
62
|
+
export type Field = FieldDefault &
|
|
63
|
+
(
|
|
64
|
+
| FieldStringType
|
|
65
|
+
| FieldStringArrayType
|
|
66
|
+
| FieldObjectType
|
|
67
|
+
| FieldArrayType
|
|
68
|
+
| FieldArrayArrayType
|
|
69
|
+
);
|
|
58
70
|
|
|
59
71
|
export type Schema = Field[];
|
|
60
72
|
|
|
61
73
|
export interface Options {
|
|
62
74
|
page?: number;
|
|
63
75
|
per_page?: number;
|
|
64
|
-
columns?: string[];
|
|
76
|
+
columns?: string[] | string;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
export type ComparisonOperator =
|
|
@@ -77,32 +89,46 @@ export type ComparisonOperator =
|
|
|
77
89
|
| "![]";
|
|
78
90
|
|
|
79
91
|
type pageInfo = {
|
|
80
|
-
|
|
92
|
+
total?: number;
|
|
81
93
|
total_pages?: number;
|
|
82
94
|
} & Options;
|
|
83
95
|
|
|
84
96
|
export type Criteria =
|
|
85
97
|
| {
|
|
86
|
-
[logic in "and" | "or"]?: Criteria;
|
|
98
|
+
[logic in "and" | "or"]?: Criteria | (string | number | boolean | null)[];
|
|
87
99
|
}
|
|
88
100
|
| {
|
|
89
101
|
[key: string]: string | number | boolean | Criteria;
|
|
90
102
|
}
|
|
91
103
|
| null;
|
|
92
104
|
|
|
105
|
+
declare global {
|
|
106
|
+
type Entries<T> = {
|
|
107
|
+
[K in keyof T]: [K, T[K]];
|
|
108
|
+
}[keyof T][];
|
|
109
|
+
|
|
110
|
+
interface ObjectConstructor {
|
|
111
|
+
entries<T extends object>(o: T): Entries<T>;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
export default class Inibase {
|
|
116
|
+
public folder: string;
|
|
94
117
|
public database: string;
|
|
95
|
-
public
|
|
96
|
-
public cache: Map<string, string>;
|
|
97
|
-
public pageInfoArray: Record<string, Record<string, number>>;
|
|
118
|
+
public table: string;
|
|
98
119
|
public pageInfo: pageInfo;
|
|
120
|
+
private cache: Map<string, string>;
|
|
121
|
+
private totalItems: Record<string, number>;
|
|
122
|
+
private salt: Buffer;
|
|
99
123
|
|
|
100
|
-
constructor(
|
|
101
|
-
this.database =
|
|
102
|
-
this.
|
|
124
|
+
constructor(database: string, mainFolder: string = ".") {
|
|
125
|
+
this.database = database;
|
|
126
|
+
this.folder = mainFolder;
|
|
127
|
+
this.table = null;
|
|
103
128
|
this.cache = new Map<string, any>();
|
|
104
|
-
this.
|
|
129
|
+
this.totalItems = {};
|
|
105
130
|
this.pageInfo = { page: 1, per_page: 15 };
|
|
131
|
+
this.salt = scryptSync(database, "salt", 32);
|
|
106
132
|
}
|
|
107
133
|
|
|
108
134
|
private throwError(
|
|
@@ -116,14 +142,14 @@ export default class Inibase {
|
|
|
116
142
|
): Error {
|
|
117
143
|
const errorMessages: Record<string, Record<string, string>> = {
|
|
118
144
|
en: {
|
|
145
|
+
FIELD_REQUIRED: "REQUIRED: {variable}",
|
|
119
146
|
NO_SCHEMA: "NO_SCHEMA: {variable}",
|
|
120
147
|
NO_ITEMS: "NO_ITEMS: {variable}",
|
|
148
|
+
NO_DATA: "NO_DATA: {variable}",
|
|
121
149
|
INVALID_ID: "INVALID_ID: {variable}",
|
|
122
150
|
INVALID_TYPE: "INVALID_TYPE: {variable}",
|
|
123
|
-
REQUIRED: "REQUIRED: {variable}",
|
|
124
|
-
NO_DATA: "NO_DATA: {variable}",
|
|
125
151
|
INVALID_OPERATOR: "INVALID_OPERATOR: {variable}",
|
|
126
|
-
|
|
152
|
+
INVALID_PARAMETERS: "PARAMETERS: {variable}",
|
|
127
153
|
},
|
|
128
154
|
// Add more languages and error messages as needed
|
|
129
155
|
};
|
|
@@ -151,148 +177,42 @@ export default class Inibase {
|
|
|
151
177
|
return new Error(errorMessage);
|
|
152
178
|
}
|
|
153
179
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (!secretKey) secretKey = this.databasePath;
|
|
165
|
-
const salt = scryptSync(secretKey.toString(), "salt", 32),
|
|
166
|
-
decipher = createDecipheriv("aes-256-cbc", salt, salt.subarray(0, 16));
|
|
167
|
-
return Number(
|
|
168
|
-
decipher.update(input as string, "hex", "utf8") + decipher.final("utf8")
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
public isValidID(input: any): boolean {
|
|
173
|
-
return Array.isArray(input)
|
|
174
|
-
? input.every(this.isValidID)
|
|
175
|
-
: typeof input === "string" && input.length === 32;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
public validateData(
|
|
179
|
-
data: Data | Data[],
|
|
180
|
-
schema: Schema,
|
|
181
|
-
skipRequiredField: boolean = false
|
|
182
|
-
): void {
|
|
183
|
-
if (Utils.isArrayOfObjects(data))
|
|
184
|
-
for (const single_data of data as Data[])
|
|
185
|
-
this.validateData(single_data, schema, skipRequiredField);
|
|
186
|
-
else if (!Array.isArray(data)) {
|
|
187
|
-
const validateFieldType = (
|
|
188
|
-
value: any,
|
|
189
|
-
field: Field | FieldType | FieldType[]
|
|
190
|
-
): boolean => {
|
|
191
|
-
if (Array.isArray(field))
|
|
192
|
-
return field.some((item) => validateFieldType(value, item));
|
|
193
|
-
switch (typeof field === "string" ? field : field.type) {
|
|
194
|
-
case "string":
|
|
195
|
-
return value === null || typeof value === "string";
|
|
196
|
-
case "number":
|
|
197
|
-
return value === null || typeof value === "number";
|
|
198
|
-
case "boolean":
|
|
199
|
-
return (
|
|
200
|
-
value === null ||
|
|
201
|
-
typeof value === "boolean" ||
|
|
202
|
-
value === "true" ||
|
|
203
|
-
value === "false"
|
|
204
|
-
);
|
|
205
|
-
case "date":
|
|
206
|
-
return value === null || value instanceof Date;
|
|
207
|
-
case "object":
|
|
208
|
-
return (
|
|
209
|
-
value === null ||
|
|
210
|
-
(typeof value === "object" &&
|
|
211
|
-
!Array.isArray(value) &&
|
|
212
|
-
value !== null)
|
|
213
|
-
);
|
|
214
|
-
case "array":
|
|
215
|
-
return (
|
|
216
|
-
value === null ||
|
|
217
|
-
(Array.isArray(value) &&
|
|
218
|
-
value.every((item) => validateFieldType(item, field)))
|
|
219
|
-
);
|
|
220
|
-
case "email":
|
|
221
|
-
return (
|
|
222
|
-
value === null ||
|
|
223
|
-
(typeof value === "string" &&
|
|
224
|
-
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value))
|
|
225
|
-
);
|
|
226
|
-
case "url":
|
|
227
|
-
return (
|
|
228
|
-
value === null ||
|
|
229
|
-
(typeof value === "string" &&
|
|
230
|
-
(value[0] === "#" ||
|
|
231
|
-
/^((https?|www):\/\/)?[a-z0-9-]+(\.[a-z0-9-]+)*\.[a-z]+(\/[^\s]*)?$/.test(
|
|
232
|
-
value
|
|
233
|
-
)))
|
|
234
|
-
);
|
|
235
|
-
case "table":
|
|
236
|
-
// feat: check if id exists
|
|
237
|
-
if (Array.isArray(value))
|
|
238
|
-
return (
|
|
239
|
-
typeof field !== "string" &&
|
|
240
|
-
field.type === "table" &&
|
|
241
|
-
((Utils.isArrayOfObjects(value) &&
|
|
242
|
-
value.every(
|
|
243
|
-
(element) =>
|
|
244
|
-
element.hasOwnProperty("id") &&
|
|
245
|
-
this.isValidID((element as Data).id)
|
|
246
|
-
)) ||
|
|
247
|
-
value.every(Utils.isNumber) ||
|
|
248
|
-
this.isValidID(value))
|
|
249
|
-
);
|
|
250
|
-
else if (Utils.isObject(value))
|
|
251
|
-
return (
|
|
252
|
-
value.hasOwnProperty("id") && this.isValidID((value as Data).id)
|
|
253
|
-
);
|
|
254
|
-
else return Utils.isNumber(value) || this.isValidID(value);
|
|
255
|
-
default:
|
|
256
|
-
return true;
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
for (const field of schema) {
|
|
260
|
-
if (data.hasOwnProperty(field.key)) {
|
|
261
|
-
if (!validateFieldType(data[field.key], field))
|
|
262
|
-
throw this.throwError("INVALID_TYPE", field.key);
|
|
263
|
-
if (
|
|
264
|
-
(field.type === "array" || field.type === "object") &&
|
|
265
|
-
field.children &&
|
|
266
|
-
Utils.isArrayOfObjects(field.children)
|
|
267
|
-
)
|
|
268
|
-
this.validateData(
|
|
269
|
-
data[field.key],
|
|
270
|
-
field.children as Schema,
|
|
271
|
-
skipRequiredField
|
|
272
|
-
);
|
|
273
|
-
} else if (field.required && !skipRequiredField)
|
|
274
|
-
throw this.throwError("REQUIRED", field.key);
|
|
275
|
-
}
|
|
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);
|
|
276
190
|
}
|
|
191
|
+
return 0;
|
|
277
192
|
}
|
|
278
193
|
|
|
279
|
-
public setTableSchema(
|
|
194
|
+
public async setTableSchema(
|
|
195
|
+
tableName: string,
|
|
196
|
+
schema: Schema
|
|
197
|
+
): Promise<void> {
|
|
280
198
|
const encodeSchema = (schema: Schema) => {
|
|
281
199
|
let RETURN: any[][] = [],
|
|
282
200
|
index = 0;
|
|
283
201
|
for (const field of schema) {
|
|
284
202
|
if (!RETURN[index]) RETURN[index] = [];
|
|
285
203
|
RETURN[index].push(
|
|
286
|
-
field.id
|
|
204
|
+
field.id
|
|
205
|
+
? UtilsServer.decodeID(field.id as string, this.salt)
|
|
206
|
+
: null
|
|
287
207
|
);
|
|
288
208
|
RETURN[index].push(field.key ?? null);
|
|
289
209
|
RETURN[index].push(field.required ?? null);
|
|
290
210
|
RETURN[index].push(field.type ?? null);
|
|
291
211
|
RETURN[index].push(
|
|
292
|
-
(field
|
|
293
|
-
field.children
|
|
294
|
-
|
|
295
|
-
|
|
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
|
|
296
216
|
: null
|
|
297
217
|
);
|
|
298
218
|
index++;
|
|
@@ -307,97 +227,78 @@ export default class Inibase {
|
|
|
307
227
|
) {
|
|
308
228
|
if (!field.id) {
|
|
309
229
|
oldIndex++;
|
|
310
|
-
field = {
|
|
311
|
-
|
|
230
|
+
field = {
|
|
231
|
+
...field,
|
|
232
|
+
id: UtilsServer.encodeID(oldIndex, this.salt),
|
|
233
|
+
};
|
|
234
|
+
} else
|
|
235
|
+
oldIndex = UtilsServer.decodeID(field.id as string, this.salt);
|
|
312
236
|
field.children = addIdToSchema(field.children as Schema, oldIndex);
|
|
313
237
|
oldIndex += field.children.length;
|
|
314
|
-
} else if (field.id)
|
|
238
|
+
} else if (field.id)
|
|
239
|
+
oldIndex = UtilsServer.decodeID(field.id as string, this.salt);
|
|
315
240
|
else {
|
|
316
241
|
oldIndex++;
|
|
317
|
-
field = {
|
|
242
|
+
field = {
|
|
243
|
+
...field,
|
|
244
|
+
id: UtilsServer.encodeID(oldIndex, this.salt),
|
|
245
|
+
};
|
|
318
246
|
}
|
|
319
247
|
return field;
|
|
320
|
-
})
|
|
321
|
-
findLastIdNumber = (schema: Schema): number => {
|
|
322
|
-
const lastField = schema[schema.length - 1];
|
|
323
|
-
if (lastField) {
|
|
324
|
-
if (
|
|
325
|
-
(lastField.type === "array" || lastField.type === "object") &&
|
|
326
|
-
Utils.isArrayOfObjects(lastField.children)
|
|
327
|
-
)
|
|
328
|
-
return findLastIdNumber(lastField.children as Schema);
|
|
329
|
-
else return this.decodeID(lastField.id as string);
|
|
330
|
-
} else return 0;
|
|
331
|
-
};
|
|
248
|
+
});
|
|
332
249
|
|
|
333
250
|
// remove id from schema
|
|
334
|
-
schema = schema.filter(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
251
|
+
schema = schema.filter(
|
|
252
|
+
(field) => !["id", "created_at", "updated_at"].includes(field.key)
|
|
253
|
+
);
|
|
254
|
+
schema = addIdToSchema(schema, this.findLastIdNumber(schema));
|
|
255
|
+
const TablePath = join(this.folder, this.database, tableName),
|
|
256
|
+
TableSchemaPath = join(TablePath, "schema");
|
|
257
|
+
if (!(await File.isExists(TablePath)))
|
|
258
|
+
await mkdir(TablePath, { recursive: true });
|
|
259
|
+
if (await File.isExists(TableSchemaPath)) {
|
|
340
260
|
// update columns files names based on field id
|
|
341
261
|
const schemaToIdsPath = (schema: any, prefix = "") => {
|
|
342
262
|
let RETURN: any = {};
|
|
343
|
-
for (const field of schema)
|
|
263
|
+
for (const field of schema)
|
|
344
264
|
if (field.children && Utils.isArrayOfObjects(field.children)) {
|
|
345
265
|
Utils.deepMerge(
|
|
346
266
|
RETURN,
|
|
347
267
|
schemaToIdsPath(
|
|
348
268
|
field.children,
|
|
349
|
-
(prefix ?? "") +
|
|
350
|
-
field.key +
|
|
351
|
-
(field.type === "array" ? ".*." : ".")
|
|
269
|
+
(prefix ?? "") + field.key + "."
|
|
352
270
|
)
|
|
353
271
|
);
|
|
354
|
-
} else if (
|
|
355
|
-
RETURN[
|
|
356
|
-
(prefix ?? "") + field.key
|
|
357
|
-
"inib"
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
return RETURN;
|
|
361
|
-
},
|
|
362
|
-
findChangedProperties = (
|
|
363
|
-
obj1: Record<string, string>,
|
|
364
|
-
obj2: Record<string, string>
|
|
365
|
-
): Record<string, string> | null => {
|
|
366
|
-
const result: Record<string, string> = {};
|
|
272
|
+
} else if (Utils.isValidID(field.id))
|
|
273
|
+
RETURN[UtilsServer.decodeID(field.id, this.salt)] =
|
|
274
|
+
(prefix ?? "") + field.key + ".inib";
|
|
367
275
|
|
|
368
|
-
|
|
369
|
-
if (obj2.hasOwnProperty(key1) && obj1[key1] !== obj2[key1]) {
|
|
370
|
-
result[obj1[key1]] = obj2[key1];
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return Object.keys(result).length ? result : null;
|
|
276
|
+
return RETURN;
|
|
375
277
|
},
|
|
376
|
-
replaceOldPathes = findChangedProperties(
|
|
377
|
-
schemaToIdsPath(this.getTableSchema(tableName)),
|
|
278
|
+
replaceOldPathes = Utils.findChangedProperties(
|
|
279
|
+
schemaToIdsPath(await this.getTableSchema(tableName)),
|
|
378
280
|
schemaToIdsPath(schema)
|
|
379
281
|
);
|
|
380
|
-
if (replaceOldPathes)
|
|
282
|
+
if (replaceOldPathes)
|
|
381
283
|
for (const [oldPath, newPath] of Object.entries(replaceOldPathes))
|
|
382
|
-
if (
|
|
383
|
-
|
|
384
|
-
}
|
|
284
|
+
if (await File.isExists(join(TablePath, oldPath)))
|
|
285
|
+
await rename(join(TablePath, oldPath), join(TablePath, newPath));
|
|
385
286
|
}
|
|
386
287
|
|
|
387
|
-
|
|
388
|
-
join(TablePath, "schema
|
|
288
|
+
await writeFile(
|
|
289
|
+
join(TablePath, "schema"),
|
|
389
290
|
JSON.stringify(encodeSchema(schema))
|
|
390
291
|
);
|
|
391
292
|
}
|
|
392
293
|
|
|
393
|
-
public getTableSchema(tableName: string): Schema | undefined {
|
|
294
|
+
public async getTableSchema(tableName: string): Promise<Schema | undefined> {
|
|
394
295
|
const decodeSchema = (encodedSchema: any) => {
|
|
395
296
|
return encodedSchema.map((field: any) =>
|
|
396
297
|
Array.isArray(field[0])
|
|
397
298
|
? decodeSchema(field)
|
|
398
299
|
: Object.fromEntries(
|
|
399
300
|
Object.entries({
|
|
400
|
-
id:
|
|
301
|
+
id: UtilsServer.encodeID(field[0], this.salt),
|
|
401
302
|
key: field[1],
|
|
402
303
|
required: field[2],
|
|
403
304
|
type: field[3],
|
|
@@ -410,10 +311,12 @@ export default class Inibase {
|
|
|
410
311
|
)
|
|
411
312
|
);
|
|
412
313
|
},
|
|
413
|
-
TableSchemaPath = join(this.
|
|
414
|
-
if (!
|
|
314
|
+
TableSchemaPath = join(this.folder, this.database, tableName, "schema");
|
|
315
|
+
if (!(await File.isExists(TableSchemaPath))) return undefined;
|
|
415
316
|
if (!this.cache.has(TableSchemaPath)) {
|
|
416
|
-
const TableSchemaPathContent =
|
|
317
|
+
const TableSchemaPathContent = await readFile(TableSchemaPath, {
|
|
318
|
+
encoding: "utf8",
|
|
319
|
+
});
|
|
417
320
|
this.cache.set(
|
|
418
321
|
TableSchemaPath,
|
|
419
322
|
TableSchemaPathContent
|
|
@@ -421,25 +324,107 @@ export default class Inibase {
|
|
|
421
324
|
: ""
|
|
422
325
|
);
|
|
423
326
|
}
|
|
327
|
+
const schema = this.cache.get(TableSchemaPath) as unknown as Schema,
|
|
328
|
+
lastIdNumber = this.findLastIdNumber(schema);
|
|
424
329
|
return [
|
|
425
|
-
{
|
|
426
|
-
|
|
330
|
+
{
|
|
331
|
+
id: UtilsServer.encodeID(0, this.salt),
|
|
332
|
+
key: "id",
|
|
333
|
+
type: "id",
|
|
334
|
+
required: true,
|
|
335
|
+
},
|
|
336
|
+
...schema,
|
|
337
|
+
{
|
|
338
|
+
id: UtilsServer.encodeID(lastIdNumber + 1, this.salt),
|
|
339
|
+
key: "created_at",
|
|
340
|
+
type: "date",
|
|
341
|
+
required: true,
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: UtilsServer.encodeID(lastIdNumber + 2, this.salt),
|
|
345
|
+
key: "updated_at",
|
|
346
|
+
type: "date",
|
|
347
|
+
required: false,
|
|
348
|
+
},
|
|
427
349
|
];
|
|
428
350
|
}
|
|
429
351
|
|
|
430
|
-
public getField
|
|
431
|
-
|
|
352
|
+
public getField<Property extends keyof Field | "children">(
|
|
353
|
+
keyPath: string,
|
|
354
|
+
schema: Schema | Field,
|
|
355
|
+
property?: Property
|
|
356
|
+
) {
|
|
357
|
+
const keyPathSplited = keyPath.split(".");
|
|
358
|
+
for (const [index, key] of keyPathSplited.entries()) {
|
|
432
359
|
if (key === "*") continue;
|
|
433
360
|
const foundItem = (schema as Schema).find((item) => item.key === key);
|
|
434
361
|
if (!foundItem) return null;
|
|
435
|
-
schema =
|
|
362
|
+
if (index === keyPathSplited.length - 1) schema = foundItem;
|
|
363
|
+
if (
|
|
436
364
|
(foundItem.type === "array" || foundItem.type === "object") &&
|
|
437
365
|
foundItem.children &&
|
|
438
366
|
Utils.isArrayOfObjects(foundItem.children)
|
|
439
|
-
|
|
440
|
-
|
|
367
|
+
)
|
|
368
|
+
schema = foundItem.children as Schema;
|
|
369
|
+
}
|
|
370
|
+
if (property) {
|
|
371
|
+
switch (property) {
|
|
372
|
+
case "type":
|
|
373
|
+
return (schema as Field).type;
|
|
374
|
+
case "children":
|
|
375
|
+
return (
|
|
376
|
+
schema as
|
|
377
|
+
| (Field & FieldObjectType)
|
|
378
|
+
| FieldArrayType
|
|
379
|
+
| FieldArrayArrayType
|
|
380
|
+
).children;
|
|
381
|
+
|
|
382
|
+
default:
|
|
383
|
+
return (schema as Field)[property as keyof Field];
|
|
384
|
+
}
|
|
385
|
+
} else return schema as Field;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
public validateData(
|
|
389
|
+
data: Data | Data[],
|
|
390
|
+
schema: Schema,
|
|
391
|
+
skipRequiredField: boolean = false
|
|
392
|
+
): void {
|
|
393
|
+
if (Utils.isArrayOfObjects(data))
|
|
394
|
+
for (const single_data of data as Data[])
|
|
395
|
+
this.validateData(single_data, schema, skipRequiredField);
|
|
396
|
+
else if (Utils.isObject(data)) {
|
|
397
|
+
for (const field of schema) {
|
|
398
|
+
if (
|
|
399
|
+
!data.hasOwnProperty(field.key) &&
|
|
400
|
+
field.required &&
|
|
401
|
+
!skipRequiredField
|
|
402
|
+
)
|
|
403
|
+
throw this.throwError("FIELD_REQUIRED", field.key);
|
|
404
|
+
if (
|
|
405
|
+
data.hasOwnProperty(field.key) &&
|
|
406
|
+
!Utils.validateFieldType(
|
|
407
|
+
data[field.key],
|
|
408
|
+
field.type,
|
|
409
|
+
(field as any)?.children &&
|
|
410
|
+
!Utils.isArrayOfObjects((field as any)?.children)
|
|
411
|
+
? (field as any)?.children
|
|
412
|
+
: undefined
|
|
413
|
+
)
|
|
414
|
+
)
|
|
415
|
+
throw this.throwError("INVALID_TYPE", field.key);
|
|
416
|
+
if (
|
|
417
|
+
(field.type === "array" || field.type === "object") &&
|
|
418
|
+
field.children &&
|
|
419
|
+
Utils.isArrayOfObjects(field.children)
|
|
420
|
+
)
|
|
421
|
+
this.validateData(
|
|
422
|
+
data[field.key],
|
|
423
|
+
field.children as Schema,
|
|
424
|
+
skipRequiredField
|
|
425
|
+
);
|
|
426
|
+
}
|
|
441
427
|
}
|
|
442
|
-
return schema as Field;
|
|
443
428
|
}
|
|
444
429
|
|
|
445
430
|
public formatData(
|
|
@@ -447,89 +432,117 @@ export default class Inibase {
|
|
|
447
432
|
schema: Schema,
|
|
448
433
|
formatOnlyAvailiableKeys?: boolean
|
|
449
434
|
): Data | Data[] {
|
|
450
|
-
|
|
435
|
+
const formatField = (
|
|
436
|
+
value: any,
|
|
437
|
+
field: Field
|
|
438
|
+
): Data | Data[] | number | string => {
|
|
439
|
+
if (Array.isArray(field.type))
|
|
440
|
+
field.type = Utils.detectFieldType(value, field.type);
|
|
441
|
+
switch (field.type) {
|
|
442
|
+
case "array":
|
|
443
|
+
if (typeof field.children === "string") {
|
|
444
|
+
if (field.type === "array" && field.children === "table") {
|
|
445
|
+
if (Array.isArray(data[field.key])) {
|
|
446
|
+
if (Utils.isArrayOfObjects(data[field.key])) {
|
|
447
|
+
if (
|
|
448
|
+
value.every(
|
|
449
|
+
(item: any) =>
|
|
450
|
+
item.hasOwnProperty("id") &&
|
|
451
|
+
(Utils.isValidID(item.id) || Utils.isNumber(item.id))
|
|
452
|
+
)
|
|
453
|
+
)
|
|
454
|
+
value.map((item: any) =>
|
|
455
|
+
Utils.isNumber(item.id)
|
|
456
|
+
? Number(item.id)
|
|
457
|
+
: UtilsServer.decodeID(item.id, this.salt)
|
|
458
|
+
);
|
|
459
|
+
} else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
460
|
+
return value.map((item: number | string) =>
|
|
461
|
+
Utils.isNumber(item)
|
|
462
|
+
? Number(item as string)
|
|
463
|
+
: UtilsServer.decodeID(item as string, this.salt)
|
|
464
|
+
);
|
|
465
|
+
} else if (Utils.isValidID(value))
|
|
466
|
+
return [UtilsServer.decodeID(value, this.salt)];
|
|
467
|
+
else if (Utils.isNumber(value)) return [Number(value)];
|
|
468
|
+
} else if (data.hasOwnProperty(field.key)) return value;
|
|
469
|
+
} else if (Utils.isArrayOfObjects(field.children))
|
|
470
|
+
return this.formatData(
|
|
471
|
+
value,
|
|
472
|
+
field.children as Schema,
|
|
473
|
+
formatOnlyAvailiableKeys
|
|
474
|
+
);
|
|
475
|
+
else if (Array.isArray(field.children))
|
|
476
|
+
return Array.isArray(value) ? value : [value];
|
|
477
|
+
break;
|
|
478
|
+
case "object":
|
|
479
|
+
if (Utils.isArrayOfObjects(field.children))
|
|
480
|
+
return this.formatData(
|
|
481
|
+
value,
|
|
482
|
+
field.children,
|
|
483
|
+
formatOnlyAvailiableKeys
|
|
484
|
+
);
|
|
485
|
+
break;
|
|
486
|
+
case "table":
|
|
487
|
+
if (Utils.isObject(value)) {
|
|
488
|
+
if (
|
|
489
|
+
value.hasOwnProperty("id") &&
|
|
490
|
+
(Utils.isValidID(value.id) || Utils.isNumber(value))
|
|
491
|
+
)
|
|
492
|
+
return Utils.isNumber(value.id)
|
|
493
|
+
? Number(value.id)
|
|
494
|
+
: UtilsServer.decodeID(value.id, this.salt);
|
|
495
|
+
} else if (Utils.isValidID(value) || Utils.isNumber(value))
|
|
496
|
+
return Utils.isNumber(value)
|
|
497
|
+
? Number(value)
|
|
498
|
+
: UtilsServer.decodeID(value, this.salt);
|
|
499
|
+
break;
|
|
500
|
+
case "password":
|
|
501
|
+
return value.length === 161 ? value : UtilsServer.hashPassword(value);
|
|
502
|
+
case "number":
|
|
503
|
+
return Utils.isNumber(value) ? Number(value) : null;
|
|
504
|
+
case "id":
|
|
505
|
+
return Utils.isNumber(value)
|
|
506
|
+
? value
|
|
507
|
+
: UtilsServer.decodeID(value, this.salt);
|
|
508
|
+
default:
|
|
509
|
+
return value;
|
|
510
|
+
}
|
|
511
|
+
return null;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
this.validateData(data, schema, formatOnlyAvailiableKeys);
|
|
515
|
+
|
|
516
|
+
if (Utils.isArrayOfObjects(data))
|
|
451
517
|
return data.map((single_data: Data) =>
|
|
452
|
-
this.formatData(single_data, schema)
|
|
518
|
+
this.formatData(single_data, schema, formatOnlyAvailiableKeys)
|
|
453
519
|
);
|
|
454
|
-
|
|
520
|
+
else if (Utils.isObject(data)) {
|
|
455
521
|
let RETURN: Data = {};
|
|
456
522
|
for (const field of schema) {
|
|
457
523
|
if (!data.hasOwnProperty(field.key)) {
|
|
524
|
+
if (formatOnlyAvailiableKeys || !field.required) continue;
|
|
458
525
|
RETURN[field.key] = this.getDefaultValue(field);
|
|
459
526
|
continue;
|
|
460
527
|
}
|
|
461
|
-
|
|
462
|
-
continue;
|
|
463
|
-
|
|
464
|
-
if (field.type === "array" || field.type === "object") {
|
|
465
|
-
if (field.children)
|
|
466
|
-
if (typeof field.children === "string") {
|
|
467
|
-
if (field.type === "array" && field.children === "table") {
|
|
468
|
-
if (Array.isArray(data[field.key])) {
|
|
469
|
-
if (Utils.isArrayOfObjects(data[field.key])) {
|
|
470
|
-
if (
|
|
471
|
-
data[field.key].every(
|
|
472
|
-
(item: any) =>
|
|
473
|
-
item.hasOwnProperty("id") &&
|
|
474
|
-
(this.isValidID(item.id) || Utils.isNumber(item.id))
|
|
475
|
-
)
|
|
476
|
-
)
|
|
477
|
-
data[field.key].map((item: any) =>
|
|
478
|
-
Utils.isNumber(item.id)
|
|
479
|
-
? parseFloat(item.id)
|
|
480
|
-
: this.decodeID(item.id)
|
|
481
|
-
);
|
|
482
|
-
} else if (
|
|
483
|
-
this.isValidID(data[field.key]) ||
|
|
484
|
-
Utils.isNumber(data[field.key])
|
|
485
|
-
)
|
|
486
|
-
RETURN[field.key] = data[field.key].map(
|
|
487
|
-
(item: number | string) =>
|
|
488
|
-
Utils.isNumber(item)
|
|
489
|
-
? parseFloat(item as string)
|
|
490
|
-
: this.decodeID(item as string)
|
|
491
|
-
);
|
|
492
|
-
} else if (this.isValidID(data[field.key]))
|
|
493
|
-
RETURN[field.key] = [this.decodeID(data[field.key])];
|
|
494
|
-
else if (Utils.isNumber(data[field.key]))
|
|
495
|
-
RETURN[field.key] = [parseFloat(data[field.key])];
|
|
496
|
-
} else if (data.hasOwnProperty(field.key))
|
|
497
|
-
RETURN[field.key] = data[field.key];
|
|
498
|
-
} else if (Utils.isArrayOfObjects(field.children))
|
|
499
|
-
RETURN[field.key] = this.formatData(
|
|
500
|
-
data[field.key],
|
|
501
|
-
field.children as Schema,
|
|
502
|
-
formatOnlyAvailiableKeys
|
|
503
|
-
);
|
|
504
|
-
} else if (field.type === "table") {
|
|
505
|
-
if (Utils.isObject(data[field.key])) {
|
|
506
|
-
if (
|
|
507
|
-
data[field.key].hasOwnProperty("id") &&
|
|
508
|
-
(this.isValidID(data[field.key].id) ||
|
|
509
|
-
Utils.isNumber(data[field.key]))
|
|
510
|
-
)
|
|
511
|
-
RETURN[field.key] = Utils.isNumber(data[field.key].id)
|
|
512
|
-
? parseFloat(data[field.key].id)
|
|
513
|
-
: this.decodeID(data[field.key].id);
|
|
514
|
-
} else if (
|
|
515
|
-
this.isValidID(data[field.key]) ||
|
|
516
|
-
Utils.isNumber(data[field.key])
|
|
517
|
-
)
|
|
518
|
-
RETURN[field.key] = Utils.isNumber(data[field.key])
|
|
519
|
-
? parseFloat(data[field.key])
|
|
520
|
-
: this.decodeID(data[field.key]);
|
|
521
|
-
} else if (field.type === "password")
|
|
522
|
-
RETURN[field.key] =
|
|
523
|
-
data[field.key].length === 161
|
|
524
|
-
? data[field.key]
|
|
525
|
-
: Utils.hashPassword(data[field.key]);
|
|
526
|
-
else RETURN[field.key] = data[field.key];
|
|
528
|
+
RETURN[field.key] = formatField(data[field.key], field);
|
|
527
529
|
}
|
|
528
530
|
return RETURN;
|
|
529
531
|
} else return [];
|
|
530
532
|
}
|
|
531
533
|
|
|
532
534
|
private getDefaultValue(field: Field): any {
|
|
535
|
+
if (Array.isArray(field.type))
|
|
536
|
+
return this.getDefaultValue({
|
|
537
|
+
...field,
|
|
538
|
+
type: field.type.sort(
|
|
539
|
+
(a: FieldType, b: FieldType) =>
|
|
540
|
+
Number(b === "array") - Number(a === "array") ||
|
|
541
|
+
Number(a === "string") - Number(b === "string") ||
|
|
542
|
+
Number(a === "number") - Number(b === "number")
|
|
543
|
+
)[0],
|
|
544
|
+
} as Field);
|
|
545
|
+
|
|
533
546
|
switch (field.type) {
|
|
534
547
|
case "array":
|
|
535
548
|
return Utils.isArrayOfObjects(field.children)
|
|
@@ -556,37 +569,55 @@ export default class Inibase {
|
|
|
556
569
|
mainPath: string,
|
|
557
570
|
data: Data | Data[]
|
|
558
571
|
): { [key: string]: string[] } {
|
|
559
|
-
const CombineData = (
|
|
572
|
+
const CombineData = (_data: Data | Data[], prefix?: string) => {
|
|
560
573
|
let RETURN: Record<
|
|
561
574
|
string,
|
|
562
575
|
string | boolean | number | null | (string | boolean | number | null)[]
|
|
563
576
|
> = {};
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
577
|
+
const combineObjectsToArray = (input: any[]) =>
|
|
578
|
+
input.reduce(
|
|
579
|
+
(r, c) => (
|
|
580
|
+
Object.keys(c).map((k) => (r[k] = [...(r[k] || []), c[k]])), r
|
|
581
|
+
),
|
|
582
|
+
{}
|
|
583
|
+
);
|
|
584
|
+
if (Utils.isArrayOfObjects(_data))
|
|
585
|
+
RETURN = combineObjectsToArray(
|
|
586
|
+
(_data as Data[]).map((single_data) => CombineData(single_data))
|
|
568
587
|
);
|
|
569
588
|
else {
|
|
570
|
-
for (const [key, value] of Object.entries(
|
|
589
|
+
for (const [key, value] of Object.entries(_data as Data)) {
|
|
571
590
|
if (Utils.isObject(value))
|
|
572
591
|
Object.assign(RETURN, CombineData(value, `${key}.`));
|
|
573
592
|
else if (Array.isArray(value)) {
|
|
574
|
-
if (Utils.isArrayOfObjects(value))
|
|
593
|
+
if (Utils.isArrayOfObjects(value)) {
|
|
594
|
+
Object.assign(
|
|
595
|
+
RETURN,
|
|
596
|
+
CombineData(
|
|
597
|
+
combineObjectsToArray(value),
|
|
598
|
+
(prefix ?? "") + key + "."
|
|
599
|
+
)
|
|
600
|
+
);
|
|
601
|
+
} else if (
|
|
602
|
+
Utils.isArrayOfArrays(value) &&
|
|
603
|
+
value.every(Utils.isArrayOfObjects)
|
|
604
|
+
)
|
|
575
605
|
Object.assign(
|
|
576
606
|
RETURN,
|
|
577
607
|
CombineData(
|
|
578
|
-
|
|
579
|
-
(prefix ?? "") + key + "
|
|
608
|
+
combineObjectsToArray(value.map(combineObjectsToArray)),
|
|
609
|
+
(prefix ?? "") + key + "."
|
|
580
610
|
)
|
|
581
611
|
);
|
|
582
|
-
else
|
|
583
|
-
RETURN[(prefix ?? "") + key] =
|
|
612
|
+
else {
|
|
613
|
+
RETURN[(prefix ?? "") + key] = File.encode(value) as
|
|
584
614
|
| boolean
|
|
585
615
|
| number
|
|
586
616
|
| string
|
|
587
617
|
| null;
|
|
618
|
+
}
|
|
588
619
|
} else
|
|
589
|
-
RETURN[(prefix ?? "") + key] =
|
|
620
|
+
RETURN[(prefix ?? "") + key] = File.encode(value) as
|
|
590
621
|
| boolean
|
|
591
622
|
| number
|
|
592
623
|
| string
|
|
@@ -598,14 +629,27 @@ export default class Inibase {
|
|
|
598
629
|
const addPathToKeys = (obj: Record<string, any>, path: string) => {
|
|
599
630
|
const newObject: Record<string, any> = {};
|
|
600
631
|
|
|
601
|
-
for (const key in obj)
|
|
602
|
-
newObject[join(path, File.encodeFileName(key, "inib"))] = obj[key];
|
|
632
|
+
for (const key in obj) newObject[join(path, key + ".inib")] = obj[key];
|
|
603
633
|
|
|
604
634
|
return newObject;
|
|
605
635
|
};
|
|
606
636
|
return addPathToKeys(CombineData(data), mainPath);
|
|
607
637
|
}
|
|
608
638
|
|
|
639
|
+
public async getOne(
|
|
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
|
+
|
|
609
653
|
public async get(
|
|
610
654
|
tableName: string,
|
|
611
655
|
where?: string | number | (string | number)[] | Criteria,
|
|
@@ -616,43 +660,43 @@ export default class Inibase {
|
|
|
616
660
|
onlyLinesNumbers?: boolean
|
|
617
661
|
): Promise<Data | Data[] | number[] | null> {
|
|
618
662
|
if (!options.columns) options.columns = [];
|
|
619
|
-
else if (
|
|
620
|
-
options.columns.
|
|
621
|
-
|
|
622
|
-
)
|
|
663
|
+
else if (!Array.isArray(options.columns))
|
|
664
|
+
options.columns = [options.columns];
|
|
665
|
+
if (options.columns.length && !(options.columns as string[]).includes("id"))
|
|
623
666
|
options.columns.push("id");
|
|
624
667
|
if (!options.page) options.page = 1;
|
|
625
668
|
if (!options.per_page) options.per_page = 15;
|
|
626
669
|
let RETURN!: Data | Data[] | null;
|
|
627
|
-
let schema = this.getTableSchema(tableName);
|
|
670
|
+
let schema = await this.getTableSchema(tableName);
|
|
628
671
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
672
|
+
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
673
|
+
if (!(await File.isExists(idFilePath))) return null;
|
|
629
674
|
const filterSchemaByColumns = (schema: Schema, columns: string[]): Schema =>
|
|
630
675
|
schema
|
|
631
676
|
.map((field) => {
|
|
632
|
-
if (columns.
|
|
677
|
+
if (columns.some((column) => column.startsWith("!")))
|
|
678
|
+
return columns.includes("!" + field.key) ? null : field;
|
|
679
|
+
if (columns.includes(field.key) || columns.includes("*"))
|
|
680
|
+
return field;
|
|
681
|
+
|
|
633
682
|
if (
|
|
634
683
|
(field.type === "array" || field.type === "object") &&
|
|
635
684
|
Utils.isArrayOfObjects(field.children) &&
|
|
636
|
-
columns.filter(
|
|
637
|
-
column
|
|
638
|
-
field.key +
|
|
639
|
-
|
|
685
|
+
columns.filter(
|
|
686
|
+
(column) =>
|
|
687
|
+
column.startsWith(field.key + ".") ||
|
|
688
|
+
column.startsWith("!" + field.key + ".")
|
|
640
689
|
).length
|
|
641
690
|
) {
|
|
642
691
|
field.children = filterSchemaByColumns(
|
|
643
692
|
field.children as Schema,
|
|
644
693
|
columns
|
|
645
|
-
.filter(
|
|
646
|
-
column
|
|
647
|
-
field.key +
|
|
648
|
-
|
|
649
|
-
)
|
|
650
|
-
.map((column) =>
|
|
651
|
-
column.replace(
|
|
652
|
-
field.key + (field.type === "array" ? ".*." : "."),
|
|
653
|
-
""
|
|
654
|
-
)
|
|
694
|
+
.filter(
|
|
695
|
+
(column) =>
|
|
696
|
+
column.startsWith(field.key + ".") ||
|
|
697
|
+
column.startsWith("!" + field.key + ".")
|
|
655
698
|
)
|
|
699
|
+
.map((column) => column.replace(field.key + ".", ""))
|
|
656
700
|
);
|
|
657
701
|
return field;
|
|
658
702
|
}
|
|
@@ -667,100 +711,251 @@ export default class Inibase {
|
|
|
667
711
|
schema: Schema,
|
|
668
712
|
linesNumber: number[],
|
|
669
713
|
prefix?: string
|
|
670
|
-
)
|
|
671
|
-
let RETURN: Data = {};
|
|
714
|
+
) => {
|
|
715
|
+
let RETURN: Record<number, Data> = {};
|
|
672
716
|
for (const field of schema) {
|
|
673
717
|
if (
|
|
674
|
-
(field.type === "array" ||
|
|
675
|
-
|
|
718
|
+
(field.type === "array" ||
|
|
719
|
+
(Array.isArray(field.type) &&
|
|
720
|
+
(field.type as any).includes("array"))) &&
|
|
721
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
722
|
+
.children
|
|
676
723
|
) {
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
.
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
724
|
+
if (
|
|
725
|
+
Utils.isArrayOfObjects(
|
|
726
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
727
|
+
.children
|
|
728
|
+
)
|
|
729
|
+
) {
|
|
730
|
+
if (
|
|
731
|
+
(
|
|
732
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
733
|
+
.children as Schema
|
|
734
|
+
).filter(
|
|
735
|
+
(children) =>
|
|
736
|
+
children.type === "array" &&
|
|
737
|
+
Utils.isArrayOfObjects(children.children)
|
|
738
|
+
).length
|
|
739
|
+
) {
|
|
740
|
+
// one of children has array field type and has children array of object = Schema
|
|
741
|
+
Object.entries(
|
|
742
|
+
(await getItemsFromSchema(
|
|
685
743
|
path,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
744
|
+
(
|
|
745
|
+
(
|
|
746
|
+
field as FieldDefault &
|
|
747
|
+
(FieldArrayType | FieldArrayArrayType)
|
|
748
|
+
).children as Schema
|
|
749
|
+
).filter(
|
|
750
|
+
(children) =>
|
|
751
|
+
children.type === "array" &&
|
|
752
|
+
Utils.isArrayOfObjects(children.children)
|
|
753
|
+
),
|
|
754
|
+
linesNumber,
|
|
755
|
+
(prefix ?? "") + field.key + "."
|
|
756
|
+
)) ?? {}
|
|
757
|
+
).forEach(([index, item]) => {
|
|
758
|
+
if (Utils.isObject(item)) {
|
|
759
|
+
if (!RETURN[index]) RETURN[index] = {};
|
|
760
|
+
if (!RETURN[index][field.key]) RETURN[index][field.key] = [];
|
|
761
|
+
for (const child_field of (
|
|
762
|
+
(
|
|
763
|
+
field as FieldDefault &
|
|
764
|
+
(FieldArrayType | FieldArrayArrayType)
|
|
765
|
+
).children as Schema
|
|
766
|
+
).filter(
|
|
767
|
+
(children) =>
|
|
768
|
+
children.type === "array" &&
|
|
769
|
+
Utils.isArrayOfObjects(children.children)
|
|
770
|
+
)) {
|
|
771
|
+
if (Utils.isObject(item[child_field.key])) {
|
|
772
|
+
Object.entries(item[child_field.key]).forEach(
|
|
773
|
+
([key, value]) => {
|
|
774
|
+
for (let _i = 0; _i < value.length; _i++) {
|
|
775
|
+
if (!RETURN[index][field.key][_i])
|
|
776
|
+
RETURN[index][field.key][_i] = {};
|
|
777
|
+
if (!RETURN[index][field.key][_i][child_field.key])
|
|
778
|
+
RETURN[index][field.key][_i][child_field.key] =
|
|
779
|
+
[];
|
|
780
|
+
value[_i].forEach((_element, _index) => {
|
|
781
|
+
if (
|
|
782
|
+
!RETURN[index][field.key][_i][child_field.key][
|
|
783
|
+
_index
|
|
784
|
+
]
|
|
785
|
+
)
|
|
786
|
+
RETURN[index][field.key][_i][child_field.key][
|
|
787
|
+
_index
|
|
788
|
+
] = {};
|
|
789
|
+
RETURN[index][field.key][_i][child_field.key][
|
|
790
|
+
_index
|
|
791
|
+
][key] = _element;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
(
|
|
801
|
+
field as FieldDefault & (FieldArrayType | FieldArrayArrayType)
|
|
802
|
+
).children = (
|
|
803
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
804
|
+
.children as Schema
|
|
805
|
+
).filter(
|
|
806
|
+
(children) =>
|
|
807
|
+
children.type !== "array" ||
|
|
808
|
+
!Utils.isArrayOfObjects(children.children)
|
|
809
|
+
);
|
|
696
810
|
}
|
|
697
|
-
} else if (Utils.isArrayOfObjects(field.children)) {
|
|
698
811
|
Object.entries(
|
|
699
812
|
(await getItemsFromSchema(
|
|
700
813
|
path,
|
|
701
|
-
field
|
|
814
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
815
|
+
.children as Schema,
|
|
702
816
|
linesNumber,
|
|
703
|
-
(prefix ?? "") +
|
|
704
|
-
field.key +
|
|
705
|
-
(field.type === "array" ? ".*." : ".")
|
|
817
|
+
(prefix ?? "") + field.key + "."
|
|
706
818
|
)) ?? {}
|
|
707
819
|
).forEach(([index, item]) => {
|
|
708
820
|
if (!RETURN[index]) RETURN[index] = {};
|
|
709
|
-
|
|
821
|
+
if (Utils.isObject(item)) {
|
|
822
|
+
if (!Object.values(item).every((i) => i === null)) {
|
|
823
|
+
if (RETURN[index][field.key])
|
|
824
|
+
Object.entries(item).forEach(([key, value], _index) => {
|
|
825
|
+
RETURN[index][field.key] = RETURN[index][field.key].map(
|
|
826
|
+
(_obj, _i) => ({ ..._obj, [key]: value[_i] })
|
|
827
|
+
);
|
|
828
|
+
});
|
|
829
|
+
else if (Object.values(item).every(Utils.isArrayOfArrays))
|
|
830
|
+
RETURN[index][field.key] = item;
|
|
831
|
+
else {
|
|
832
|
+
RETURN[index][field.key] = [];
|
|
833
|
+
Object.entries(item).forEach(([key, value]) => {
|
|
834
|
+
for (let _i = 0; _i < value.length; _i++) {
|
|
835
|
+
if (!RETURN[index][field.key][_i])
|
|
836
|
+
RETURN[index][field.key][_i] = {};
|
|
837
|
+
RETURN[index][field.key][_i][key] = value[_i];
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
} else RETURN[index][field.key] = null;
|
|
842
|
+
} else RETURN[index][field.key] = item;
|
|
710
843
|
});
|
|
844
|
+
} else if (
|
|
845
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
846
|
+
.children === "table" ||
|
|
847
|
+
(Array.isArray(
|
|
848
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
849
|
+
.children
|
|
850
|
+
) &&
|
|
851
|
+
(
|
|
852
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
853
|
+
.children as FieldType[]
|
|
854
|
+
).includes("table"))
|
|
855
|
+
) {
|
|
856
|
+
if (options.columns)
|
|
857
|
+
options.columns = (options.columns as string[])
|
|
858
|
+
.filter((column) => column.includes(`${field.key}.`))
|
|
859
|
+
.map((column) => column.replace(`${field.key}.`, ""));
|
|
860
|
+
const [items, total_lines] = await File.get(
|
|
861
|
+
join(path, (prefix ?? "") + field.key + ".inib"),
|
|
862
|
+
linesNumber,
|
|
863
|
+
field.type,
|
|
864
|
+
(field as FieldDefault & (FieldArrayType | FieldArrayArrayType))
|
|
865
|
+
.children as FieldType | FieldType[],
|
|
866
|
+
this.salt
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
870
|
+
for (const [index, item] of Object.entries(items)) {
|
|
871
|
+
if (!RETURN[index]) RETURN[index] = {};
|
|
872
|
+
RETURN[index][field.key] = item
|
|
873
|
+
? await this.get(field.key, item as number, options)
|
|
874
|
+
: this.getDefaultValue(field);
|
|
875
|
+
}
|
|
876
|
+
} else if (
|
|
877
|
+
await File.isExists(
|
|
878
|
+
join(path, (prefix ?? "") + field.key + ".inib")
|
|
879
|
+
)
|
|
880
|
+
) {
|
|
881
|
+
const [items, total_lines] = await File.get(
|
|
882
|
+
join(path, (prefix ?? "") + field.key + ".inib"),
|
|
883
|
+
linesNumber,
|
|
884
|
+
field.type,
|
|
885
|
+
(field as any)?.children,
|
|
886
|
+
this.salt
|
|
887
|
+
);
|
|
888
|
+
|
|
889
|
+
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
890
|
+
for (const [index, item] of Object.entries(items)) {
|
|
891
|
+
if (!RETURN[index]) RETURN[index] = {};
|
|
892
|
+
RETURN[index][field.key] = item ?? this.getDefaultValue(field);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
} else if (field.type === "object") {
|
|
896
|
+
for (const [index, item] of Object.entries(
|
|
897
|
+
(await getItemsFromSchema(
|
|
898
|
+
path,
|
|
899
|
+
field.children as Schema,
|
|
900
|
+
linesNumber,
|
|
901
|
+
(prefix ?? "") + field.key + "."
|
|
902
|
+
)) ?? {}
|
|
903
|
+
)) {
|
|
904
|
+
if (!RETURN[index]) RETURN[index] = {};
|
|
905
|
+
if (Utils.isObject(item)) {
|
|
906
|
+
if (!Object.values(item).every((i) => i === null))
|
|
907
|
+
RETURN[index][field.key] = item;
|
|
908
|
+
else RETURN[index][field.key] = null;
|
|
909
|
+
} else RETURN[index][field.key] = null;
|
|
711
910
|
}
|
|
712
911
|
} else if (field.type === "table") {
|
|
713
912
|
if (
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
)
|
|
913
|
+
(await File.isExists(
|
|
914
|
+
join(this.folder, this.database, field.key)
|
|
915
|
+
)) &&
|
|
916
|
+
(await File.isExists(
|
|
917
|
+
join(path, (prefix ?? "") + field.key + ".inib")
|
|
918
|
+
))
|
|
721
919
|
) {
|
|
722
920
|
if (options.columns)
|
|
723
921
|
options.columns = (options.columns as string[])
|
|
724
922
|
.filter(
|
|
725
923
|
(column) =>
|
|
726
924
|
column.includes(`${field.key}.`) &&
|
|
727
|
-
!column.includes(`${field.key}
|
|
925
|
+
!column.includes(`${field.key}.`)
|
|
728
926
|
)
|
|
729
927
|
.map((column) => column.replace(`${field.key}.`, ""));
|
|
730
|
-
|
|
731
|
-
(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
)) {
|
|
928
|
+
const [items, total_lines] = await File.get(
|
|
929
|
+
join(path, (prefix ?? "") + field.key + ".inib"),
|
|
930
|
+
linesNumber,
|
|
931
|
+
"number",
|
|
932
|
+
undefined,
|
|
933
|
+
this.salt
|
|
934
|
+
);
|
|
935
|
+
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
936
|
+
for (const [index, item] of Object.entries(items)) {
|
|
740
937
|
if (!RETURN[index]) RETURN[index] = {};
|
|
741
|
-
RETURN[index][field.key] =
|
|
742
|
-
? await this.get(field.key,
|
|
938
|
+
RETURN[index][field.key] = item
|
|
939
|
+
? await this.get(field.key, item as number, options)
|
|
743
940
|
: this.getDefaultValue(field);
|
|
744
941
|
}
|
|
745
942
|
}
|
|
746
943
|
} else if (
|
|
747
|
-
|
|
748
|
-
join(path, File.encodeFileName((prefix ?? "") + field.key, "inib"))
|
|
749
|
-
)
|
|
944
|
+
await File.isExists(join(path, (prefix ?? "") + field.key + ".inib"))
|
|
750
945
|
) {
|
|
751
|
-
|
|
752
|
-
(
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
946
|
+
const [items, total_lines] = await File.get(
|
|
947
|
+
join(path, (prefix ?? "") + field.key + ".inib"),
|
|
948
|
+
linesNumber,
|
|
949
|
+
field.type,
|
|
950
|
+
(field as any)?.children,
|
|
951
|
+
this.salt
|
|
952
|
+
);
|
|
953
|
+
|
|
954
|
+
this.totalItems[tableName + "-" + field.key] = total_lines;
|
|
955
|
+
for (const [index, item] of Object.entries(items)) {
|
|
761
956
|
if (!RETURN[index]) RETURN[index] = {};
|
|
762
957
|
RETURN[index][field.key] = item ?? this.getDefaultValue(field);
|
|
763
|
-
}
|
|
958
|
+
}
|
|
764
959
|
}
|
|
765
960
|
}
|
|
766
961
|
return RETURN;
|
|
@@ -769,7 +964,7 @@ export default class Inibase {
|
|
|
769
964
|
// Display all data
|
|
770
965
|
RETURN = Object.values(
|
|
771
966
|
await getItemsFromSchema(
|
|
772
|
-
join(this.
|
|
967
|
+
join(this.folder, this.database, tableName),
|
|
773
968
|
schema,
|
|
774
969
|
Array.from(
|
|
775
970
|
{ length: options.per_page },
|
|
@@ -780,20 +975,22 @@ export default class Inibase {
|
|
|
780
975
|
)
|
|
781
976
|
)
|
|
782
977
|
);
|
|
783
|
-
} else if (
|
|
978
|
+
} else if (Utils.isValidID(where) || Utils.isNumber(where)) {
|
|
784
979
|
let Ids = where as string | number | (string | number)[];
|
|
785
980
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
786
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
787
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
788
981
|
const [lineNumbers, countItems] = await File.search(
|
|
789
982
|
idFilePath,
|
|
790
|
-
"number",
|
|
791
983
|
"[]",
|
|
792
984
|
Utils.isNumber(Ids)
|
|
793
|
-
? Ids.map((id) =>
|
|
794
|
-
: Ids.map((id) =>
|
|
985
|
+
? Ids.map((id) => Number(id as string))
|
|
986
|
+
: Ids.map((id) => UtilsServer.decodeID(id as string, this.salt)),
|
|
795
987
|
undefined,
|
|
796
|
-
|
|
988
|
+
"number",
|
|
989
|
+
undefined,
|
|
990
|
+
Ids.length,
|
|
991
|
+
0,
|
|
992
|
+
false,
|
|
993
|
+
this.salt
|
|
797
994
|
);
|
|
798
995
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
799
996
|
throw this.throwError(
|
|
@@ -802,16 +999,17 @@ export default class Inibase {
|
|
|
802
999
|
);
|
|
803
1000
|
RETURN = Object.values(
|
|
804
1001
|
(await getItemsFromSchema(
|
|
805
|
-
join(this.
|
|
1002
|
+
join(this.folder, this.database, tableName),
|
|
806
1003
|
schema,
|
|
807
1004
|
Object.keys(lineNumbers).map(Number)
|
|
808
1005
|
)) ?? {}
|
|
809
1006
|
);
|
|
810
1007
|
if (RETURN.length && !Array.isArray(where)) RETURN = RETURN[0];
|
|
811
|
-
} else if (
|
|
1008
|
+
} else if (Utils.isObject(where)) {
|
|
812
1009
|
// Criteria
|
|
813
1010
|
const FormatObjectCriteriaValue = (
|
|
814
|
-
value: string
|
|
1011
|
+
value: string,
|
|
1012
|
+
isParentArray: boolean = false
|
|
815
1013
|
): [ComparisonOperator, string | number | boolean | null] => {
|
|
816
1014
|
switch (value[0]) {
|
|
817
1015
|
case ">":
|
|
@@ -838,10 +1036,19 @@ export default class Inibase {
|
|
|
838
1036
|
value.slice(3) as string | number,
|
|
839
1037
|
]
|
|
840
1038
|
: [
|
|
841
|
-
value.slice(0, 1) as ComparisonOperator,
|
|
1039
|
+
(value.slice(0, 1) + "=") as ComparisonOperator,
|
|
842
1040
|
value.slice(1) as string | number,
|
|
843
1041
|
];
|
|
844
1042
|
case "=":
|
|
1043
|
+
return isParentArray
|
|
1044
|
+
? [
|
|
1045
|
+
value.slice(0, 1) as ComparisonOperator,
|
|
1046
|
+
value.slice(1) as string | number,
|
|
1047
|
+
]
|
|
1048
|
+
: [
|
|
1049
|
+
value.slice(0, 1) as ComparisonOperator,
|
|
1050
|
+
(value.slice(1) + ",") as string,
|
|
1051
|
+
];
|
|
845
1052
|
case "*":
|
|
846
1053
|
return [
|
|
847
1054
|
value.slice(0, 1) as ComparisonOperator,
|
|
@@ -855,11 +1062,14 @@ export default class Inibase {
|
|
|
855
1062
|
const applyCriteria = async (
|
|
856
1063
|
criteria?: Criteria,
|
|
857
1064
|
allTrue?: boolean
|
|
858
|
-
): Promise<Data | null> => {
|
|
859
|
-
let RETURN: Data = {};
|
|
1065
|
+
): Promise<Record<number, Data> | null> => {
|
|
1066
|
+
let RETURN: Record<number, Data> = {};
|
|
860
1067
|
if (!criteria) return null;
|
|
861
|
-
if (criteria.and &&
|
|
862
|
-
const searchResult = await applyCriteria(
|
|
1068
|
+
if (criteria.and && Utils.isObject(criteria.and)) {
|
|
1069
|
+
const searchResult = await applyCriteria(
|
|
1070
|
+
criteria.and as Criteria,
|
|
1071
|
+
true
|
|
1072
|
+
);
|
|
863
1073
|
if (searchResult) {
|
|
864
1074
|
RETURN = Utils.deepMerge(
|
|
865
1075
|
RETURN,
|
|
@@ -875,160 +1085,159 @@ export default class Inibase {
|
|
|
875
1085
|
} else return null;
|
|
876
1086
|
}
|
|
877
1087
|
|
|
878
|
-
if (criteria.or &&
|
|
879
|
-
const searchResult = await applyCriteria(
|
|
1088
|
+
if (criteria.or && Utils.isObject(criteria.or)) {
|
|
1089
|
+
const searchResult = await applyCriteria(
|
|
1090
|
+
criteria.or as Criteria,
|
|
1091
|
+
false
|
|
1092
|
+
);
|
|
880
1093
|
delete criteria.or;
|
|
881
1094
|
if (searchResult) RETURN = Utils.deepMerge(RETURN, searchResult);
|
|
882
1095
|
}
|
|
883
1096
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const searchCriteria = value.or
|
|
911
|
-
.map(
|
|
912
|
-
(
|
|
913
|
-
single_or
|
|
914
|
-
): [ComparisonOperator, string | number | boolean | null] =>
|
|
915
|
-
typeof single_or === "string"
|
|
916
|
-
? FormatObjectCriteriaValue(single_or)
|
|
917
|
-
: ["=", single_or]
|
|
1097
|
+
if (Object.keys(criteria).length > 0) {
|
|
1098
|
+
if (allTrue === undefined) allTrue = true;
|
|
1099
|
+
|
|
1100
|
+
let index = -1;
|
|
1101
|
+
for (const [key, value] of Object.entries(criteria)) {
|
|
1102
|
+
const field = this.getField(key, schema as Schema) as Field;
|
|
1103
|
+
index++;
|
|
1104
|
+
let searchOperator:
|
|
1105
|
+
| ComparisonOperator
|
|
1106
|
+
| ComparisonOperator[]
|
|
1107
|
+
| undefined = undefined,
|
|
1108
|
+
searchComparedAtValue:
|
|
1109
|
+
| string
|
|
1110
|
+
| number
|
|
1111
|
+
| boolean
|
|
1112
|
+
| null
|
|
1113
|
+
| (string | number | boolean | null)[]
|
|
1114
|
+
| undefined = undefined,
|
|
1115
|
+
searchLogicalOperator: "and" | "or" | undefined = undefined;
|
|
1116
|
+
if (Utils.isObject(value)) {
|
|
1117
|
+
if (
|
|
1118
|
+
(value as Criteria)?.or &&
|
|
1119
|
+
Array.isArray((value as Criteria).or)
|
|
1120
|
+
) {
|
|
1121
|
+
const searchCriteria = (
|
|
1122
|
+
(value as Criteria).or as (string | number | boolean)[]
|
|
918
1123
|
)
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1124
|
+
.map(
|
|
1125
|
+
(
|
|
1126
|
+
single_or
|
|
1127
|
+
): [ComparisonOperator, string | number | boolean | null] =>
|
|
1128
|
+
typeof single_or === "string"
|
|
1129
|
+
? FormatObjectCriteriaValue(single_or)
|
|
1130
|
+
: ["=", single_or]
|
|
1131
|
+
)
|
|
1132
|
+
.filter((a) => a) as [ComparisonOperator, string | number][];
|
|
1133
|
+
if (searchCriteria.length > 0) {
|
|
1134
|
+
searchOperator = searchCriteria.map(
|
|
1135
|
+
(single_or) => single_or[0]
|
|
1136
|
+
);
|
|
1137
|
+
searchComparedAtValue = searchCriteria.map(
|
|
1138
|
+
(single_or) => single_or[1]
|
|
1139
|
+
);
|
|
1140
|
+
searchLogicalOperator = "or";
|
|
1141
|
+
}
|
|
1142
|
+
delete (value as Criteria).or;
|
|
928
1143
|
}
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
1144
|
+
if (
|
|
1145
|
+
(value as Criteria)?.and &&
|
|
1146
|
+
Array.isArray((value as Criteria).and)
|
|
1147
|
+
) {
|
|
1148
|
+
const searchCriteria = (
|
|
1149
|
+
(value as Criteria).and as (string | number | boolean)[]
|
|
1150
|
+
)
|
|
1151
|
+
.map(
|
|
1152
|
+
(
|
|
1153
|
+
single_and
|
|
1154
|
+
): [ComparisonOperator, string | number | boolean | null] =>
|
|
1155
|
+
typeof single_and === "string"
|
|
1156
|
+
? FormatObjectCriteriaValue(single_and)
|
|
1157
|
+
: ["=", single_and]
|
|
1158
|
+
)
|
|
1159
|
+
.filter((a) => a) as [ComparisonOperator, string | number][];
|
|
1160
|
+
if (searchCriteria.length > 0) {
|
|
1161
|
+
searchOperator = searchCriteria.map(
|
|
1162
|
+
(single_and) => single_and[0]
|
|
1163
|
+
);
|
|
1164
|
+
searchComparedAtValue = searchCriteria.map(
|
|
1165
|
+
(single_and) => single_and[1]
|
|
1166
|
+
);
|
|
1167
|
+
searchLogicalOperator = "and";
|
|
1168
|
+
}
|
|
1169
|
+
delete (value as Criteria).and;
|
|
1170
|
+
}
|
|
1171
|
+
} else if (Array.isArray(value)) {
|
|
1172
|
+
const searchCriteria = value
|
|
933
1173
|
.map(
|
|
934
1174
|
(
|
|
935
|
-
|
|
1175
|
+
single
|
|
936
1176
|
): [ComparisonOperator, string | number | boolean | null] =>
|
|
937
|
-
typeof
|
|
938
|
-
? FormatObjectCriteriaValue(
|
|
939
|
-
: ["=",
|
|
1177
|
+
typeof single === "string"
|
|
1178
|
+
? FormatObjectCriteriaValue(single)
|
|
1179
|
+
: ["=", single]
|
|
940
1180
|
)
|
|
941
1181
|
.filter((a) => a) as [ComparisonOperator, string | number][];
|
|
942
1182
|
if (searchCriteria.length > 0) {
|
|
943
|
-
searchOperator = searchCriteria.map(
|
|
944
|
-
(single_and) => single_and[0]
|
|
945
|
-
);
|
|
1183
|
+
searchOperator = searchCriteria.map((single) => single[0]);
|
|
946
1184
|
searchComparedAtValue = searchCriteria.map(
|
|
947
|
-
(
|
|
1185
|
+
(single) => single[1]
|
|
948
1186
|
);
|
|
949
1187
|
searchLogicalOperator = "and";
|
|
950
1188
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
? FormatObjectCriteriaValue(single)
|
|
961
|
-
: ["=", single]
|
|
962
|
-
)
|
|
963
|
-
.filter((a) => a) as [ComparisonOperator, string | number][];
|
|
964
|
-
if (searchCriteria.length > 0) {
|
|
965
|
-
searchOperator = searchCriteria.map((single) => single[0]);
|
|
966
|
-
searchComparedAtValue = searchCriteria.map((single) => single[1]);
|
|
967
|
-
searchLogicalOperator = "and";
|
|
968
|
-
}
|
|
969
|
-
} else if (typeof value === "string") {
|
|
970
|
-
const ComparisonOperatorValue = FormatObjectCriteriaValue(value);
|
|
971
|
-
if (ComparisonOperatorValue) {
|
|
972
|
-
searchOperator = ComparisonOperatorValue[0];
|
|
973
|
-
searchComparedAtValue = ComparisonOperatorValue[1];
|
|
1189
|
+
} else if (typeof value === "string") {
|
|
1190
|
+
const ComparisonOperatorValue = FormatObjectCriteriaValue(value);
|
|
1191
|
+
if (ComparisonOperatorValue) {
|
|
1192
|
+
searchOperator = ComparisonOperatorValue[0];
|
|
1193
|
+
searchComparedAtValue = ComparisonOperatorValue[1];
|
|
1194
|
+
}
|
|
1195
|
+
} else {
|
|
1196
|
+
searchOperator = "=";
|
|
1197
|
+
searchComparedAtValue = value as number | boolean;
|
|
974
1198
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
searchComparedAtValue = value;
|
|
978
|
-
}
|
|
979
|
-
if (searchOperator && searchComparedAtValue) {
|
|
980
|
-
const [searchResult, totlaItems] = await File.search(
|
|
981
|
-
join(
|
|
982
|
-
this.databasePath,
|
|
983
|
-
tableName,
|
|
984
|
-
File.encodeFileName(key, "inib")
|
|
985
|
-
),
|
|
986
|
-
this.getField(key, schema as Schema)?.type ?? "string",
|
|
1199
|
+
const [searchResult, total_lines] = await File.search(
|
|
1200
|
+
join(this.folder, this.database, tableName, key + ".inib"),
|
|
987
1201
|
searchOperator,
|
|
988
1202
|
searchComparedAtValue,
|
|
989
1203
|
searchLogicalOperator,
|
|
1204
|
+
field?.type,
|
|
1205
|
+
(field as any)?.children,
|
|
990
1206
|
options.per_page,
|
|
991
1207
|
(options.page as number) - 1 * (options.per_page as number) + 1,
|
|
992
|
-
true
|
|
1208
|
+
true,
|
|
1209
|
+
this.salt
|
|
993
1210
|
);
|
|
994
1211
|
if (searchResult) {
|
|
995
1212
|
RETURN = Utils.deepMerge(RETURN, searchResult);
|
|
996
|
-
|
|
997
|
-
|
|
1213
|
+
this.totalItems[tableName + "-" + key] = total_lines;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
if (allTrue && index > 0) {
|
|
1217
|
+
if (!Object.keys(RETURN).length) RETURN = {};
|
|
1218
|
+
RETURN = Object.fromEntries(
|
|
1219
|
+
Object.entries(RETURN).filter(
|
|
1220
|
+
([_index, item]) => Object.keys(item).length > index
|
|
1221
|
+
)
|
|
1222
|
+
);
|
|
1223
|
+
if (!Object.keys(RETURN).length) RETURN = {};
|
|
998
1224
|
}
|
|
999
1225
|
}
|
|
1000
1226
|
}
|
|
1001
|
-
|
|
1227
|
+
|
|
1228
|
+
return Object.keys(RETURN).length ? RETURN : null;
|
|
1002
1229
|
};
|
|
1003
1230
|
|
|
1004
|
-
RETURN = await applyCriteria(where);
|
|
1231
|
+
RETURN = await applyCriteria(where as Criteria);
|
|
1005
1232
|
if (RETURN) {
|
|
1006
1233
|
if (onlyLinesNumbers) return Object.keys(RETURN).map(Number);
|
|
1007
1234
|
const alreadyExistsColumns = Object.keys(Object.values(RETURN)[0]).map(
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
greatestColumnTotalItems = alreadyExistsColumns.reduce(
|
|
1011
|
-
(maxItem: string, currentItem: string) =>
|
|
1012
|
-
this.pageInfoArray[currentItem]?.total_items ||
|
|
1013
|
-
(0 > (this.pageInfoArray[maxItem]?.total_items || 0) &&
|
|
1014
|
-
this.pageInfoArray[currentItem].total_items)
|
|
1015
|
-
? currentItem
|
|
1016
|
-
: maxItem,
|
|
1017
|
-
""
|
|
1018
|
-
);
|
|
1019
|
-
if (greatestColumnTotalItems)
|
|
1020
|
-
this.pageInfo = {
|
|
1021
|
-
...(({ columns, ...restOFOptions }) => restOFOptions)(options),
|
|
1022
|
-
...this.pageInfoArray[greatestColumnTotalItems],
|
|
1023
|
-
total_pages: Math.ceil(
|
|
1024
|
-
this.pageInfoArray[greatestColumnTotalItems].total_items /
|
|
1025
|
-
options.per_page
|
|
1026
|
-
),
|
|
1027
|
-
};
|
|
1235
|
+
(key) => parse(key).name
|
|
1236
|
+
);
|
|
1028
1237
|
RETURN = Object.values(
|
|
1029
1238
|
Utils.deepMerge(
|
|
1030
1239
|
await getItemsFromSchema(
|
|
1031
|
-
join(this.
|
|
1240
|
+
join(this.folder, this.database, tableName),
|
|
1032
1241
|
schema.filter(
|
|
1033
1242
|
(field) => !alreadyExistsColumns.includes(field.key)
|
|
1034
1243
|
),
|
|
@@ -1039,132 +1248,162 @@ export default class Inibase {
|
|
|
1039
1248
|
);
|
|
1040
1249
|
}
|
|
1041
1250
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1251
|
+
if (
|
|
1252
|
+
!RETURN ||
|
|
1253
|
+
(Utils.isObject(RETURN) && !Object.keys(RETURN).length) ||
|
|
1254
|
+
(Array.isArray(RETURN) && !RETURN.length)
|
|
1255
|
+
)
|
|
1256
|
+
return null;
|
|
1257
|
+
|
|
1258
|
+
const greatestTotalItems = Math.max(
|
|
1259
|
+
...Object.entries(this.totalItems)
|
|
1260
|
+
.filter(([k]) => k.startsWith(tableName + "-"))
|
|
1261
|
+
.map(([, v]) => v)
|
|
1262
|
+
);
|
|
1263
|
+
this.pageInfo = {
|
|
1264
|
+
...(({ columns, ...restOfOptions }) => restOfOptions)(options),
|
|
1265
|
+
total_pages: Math.ceil(greatestTotalItems / options.per_page),
|
|
1266
|
+
total: greatestTotalItems,
|
|
1267
|
+
};
|
|
1268
|
+
return RETURN;
|
|
1053
1269
|
}
|
|
1054
1270
|
|
|
1055
1271
|
public async post(
|
|
1056
1272
|
tableName: string,
|
|
1057
|
-
data: Data | Data[]
|
|
1058
|
-
|
|
1059
|
-
|
|
1273
|
+
data: Data | Data[],
|
|
1274
|
+
options: Options = {
|
|
1275
|
+
page: 1,
|
|
1276
|
+
per_page: 15,
|
|
1277
|
+
},
|
|
1278
|
+
returnPostedData: boolean = true
|
|
1279
|
+
): Promise<Data | Data[] | null | void> {
|
|
1280
|
+
const schema = await this.getTableSchema(tableName);
|
|
1060
1281
|
let RETURN: Data | Data[] | null | undefined;
|
|
1061
1282
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1062
|
-
const idFilePath = join(this.
|
|
1063
|
-
let last_id =
|
|
1064
|
-
? Number(
|
|
1283
|
+
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
1284
|
+
let last_id = (await File.isExists(idFilePath))
|
|
1285
|
+
? Number(
|
|
1286
|
+
Object.values(
|
|
1287
|
+
(await File.get(idFilePath, -1, "number", undefined, this.salt))[0]
|
|
1288
|
+
)[0]
|
|
1289
|
+
)
|
|
1065
1290
|
: 0;
|
|
1066
1291
|
if (Utils.isArrayOfObjects(data))
|
|
1067
1292
|
(data as Data[]).forEach((single_data, index) => {
|
|
1068
1293
|
if (!RETURN) RETURN = [];
|
|
1069
|
-
RETURN[index] = (({ id, updated_at, created_at, ...rest }) =>
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1294
|
+
RETURN[index] = (({ id, updated_at, created_at, ...rest }) => ({
|
|
1295
|
+
id: ++last_id,
|
|
1296
|
+
...rest,
|
|
1297
|
+
created_at: new Date(),
|
|
1298
|
+
}))(single_data);
|
|
1074
1299
|
});
|
|
1075
|
-
else
|
|
1076
|
-
RETURN = (({ id, updated_at, created_at, ...rest }) =>
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
}
|
|
1300
|
+
else
|
|
1301
|
+
RETURN = (({ id, updated_at, created_at, ...rest }) => ({
|
|
1302
|
+
id: ++last_id,
|
|
1303
|
+
...rest,
|
|
1304
|
+
created_at: new Date(),
|
|
1305
|
+
}))(data as Data);
|
|
1082
1306
|
if (!RETURN) throw this.throwError("NO_DATA");
|
|
1083
|
-
|
|
1307
|
+
|
|
1084
1308
|
RETURN = this.formatData(RETURN, schema);
|
|
1085
1309
|
const pathesContents = this.joinPathesContents(
|
|
1086
|
-
join(this.
|
|
1310
|
+
join(this.folder, this.database, tableName),
|
|
1087
1311
|
RETURN
|
|
1088
1312
|
);
|
|
1089
|
-
for (const [path, content] of Object.entries(pathesContents))
|
|
1090
|
-
|
|
1313
|
+
for await (const [path, content] of Object.entries(pathesContents))
|
|
1314
|
+
await appendFile(
|
|
1091
1315
|
path,
|
|
1092
|
-
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1093
|
-
|
|
1316
|
+
(Array.isArray(content) ? content.join("\n") : content ?? "") + "\n"
|
|
1317
|
+
);
|
|
1318
|
+
|
|
1319
|
+
if (returnPostedData)
|
|
1320
|
+
return this.get(
|
|
1321
|
+
tableName,
|
|
1322
|
+
Utils.isArrayOfObjects(RETURN)
|
|
1323
|
+
? RETURN.map((data: Data) => data.id)
|
|
1324
|
+
: ((RETURN as Data).id as number),
|
|
1325
|
+
options
|
|
1094
1326
|
);
|
|
1095
|
-
return Utils.isArrayOfObjects(RETURN)
|
|
1096
|
-
? RETURN.map((data: Data) => {
|
|
1097
|
-
data.id = this.encodeID(data.id as number);
|
|
1098
|
-
return data;
|
|
1099
|
-
})
|
|
1100
|
-
: { ...RETURN, id: this.encodeID((RETURN as Data).id as number) };
|
|
1101
1327
|
}
|
|
1102
1328
|
|
|
1103
1329
|
public async put(
|
|
1104
1330
|
tableName: string,
|
|
1105
1331
|
data: Data | Data[],
|
|
1106
|
-
where?: number | string | (number | string)[] | Criteria
|
|
1107
|
-
|
|
1108
|
-
|
|
1332
|
+
where?: number | string | (number | string)[] | Criteria,
|
|
1333
|
+
options: Options = {
|
|
1334
|
+
page: 1,
|
|
1335
|
+
per_page: 15,
|
|
1336
|
+
},
|
|
1337
|
+
returnPostedData: boolean = true
|
|
1338
|
+
): Promise<Data | Data[] | null | void> {
|
|
1339
|
+
const schema = await this.getTableSchema(tableName);
|
|
1109
1340
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1110
|
-
this.
|
|
1341
|
+
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
1342
|
+
if (!(await File.isExists(idFilePath)))
|
|
1343
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1111
1344
|
data = this.formatData(data, schema, true);
|
|
1112
1345
|
if (!where) {
|
|
1113
1346
|
if (Utils.isArrayOfObjects(data)) {
|
|
1114
1347
|
if (
|
|
1115
1348
|
!(data as Data[]).every(
|
|
1116
|
-
(item) => item.hasOwnProperty("id") &&
|
|
1349
|
+
(item) => item.hasOwnProperty("id") && Utils.isValidID(item.id)
|
|
1117
1350
|
)
|
|
1118
1351
|
)
|
|
1119
1352
|
throw this.throwError("INVALID_ID");
|
|
1120
|
-
|
|
1353
|
+
return this.put(
|
|
1121
1354
|
tableName,
|
|
1122
1355
|
data,
|
|
1123
1356
|
(data as Data[]).map((item) => item.id)
|
|
1124
1357
|
);
|
|
1125
1358
|
} else if (data.hasOwnProperty("id")) {
|
|
1126
|
-
if (!
|
|
1359
|
+
if (!Utils.isValidID((data as Data).id))
|
|
1127
1360
|
throw this.throwError("INVALID_ID", (data as Data).id);
|
|
1128
|
-
|
|
1361
|
+
return this.put(
|
|
1129
1362
|
tableName,
|
|
1130
1363
|
data,
|
|
1131
|
-
|
|
1364
|
+
UtilsServer.decodeID((data as Data).id as string, this.salt)
|
|
1132
1365
|
);
|
|
1133
1366
|
} else {
|
|
1134
1367
|
const pathesContents = this.joinPathesContents(
|
|
1135
|
-
join(this.
|
|
1368
|
+
join(this.folder, this.database, tableName),
|
|
1136
1369
|
Utils.isArrayOfObjects(data)
|
|
1137
1370
|
? (data as Data[]).map((item) => ({
|
|
1138
|
-
...item,
|
|
1371
|
+
...(({ id, ...restOfData }) => restOfData)(item),
|
|
1139
1372
|
updated_at: new Date(),
|
|
1140
1373
|
}))
|
|
1141
|
-
: {
|
|
1374
|
+
: {
|
|
1375
|
+
...(({ id, ...restOfData }) => restOfData)(data as Data),
|
|
1376
|
+
updated_at: new Date(),
|
|
1377
|
+
}
|
|
1142
1378
|
);
|
|
1143
1379
|
for (const [path, content] of Object.entries(pathesContents))
|
|
1144
1380
|
await File.replace(path, content);
|
|
1381
|
+
if (returnPostedData) return this.get(tableName, where, options);
|
|
1145
1382
|
}
|
|
1146
|
-
} else if (
|
|
1383
|
+
} else if (Utils.isValidID(where)) {
|
|
1147
1384
|
let Ids = where as string | string[];
|
|
1148
1385
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
1149
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1150
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
1151
1386
|
const [lineNumbers, countItems] = await File.search(
|
|
1152
1387
|
idFilePath,
|
|
1153
|
-
"number",
|
|
1154
1388
|
"[]",
|
|
1155
|
-
Ids.map((id) =>
|
|
1389
|
+
Ids.map((id) => UtilsServer.decodeID(id, this.salt)),
|
|
1390
|
+
undefined,
|
|
1391
|
+
"number",
|
|
1156
1392
|
undefined,
|
|
1157
|
-
Ids.length
|
|
1393
|
+
Ids.length,
|
|
1394
|
+
0,
|
|
1395
|
+
false,
|
|
1396
|
+
this.salt
|
|
1158
1397
|
);
|
|
1159
1398
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1160
1399
|
throw this.throwError("INVALID_ID");
|
|
1161
|
-
|
|
1400
|
+
return this.put(tableName, data, Object.keys(lineNumbers).map(Number));
|
|
1162
1401
|
} else if (Utils.isNumber(where)) {
|
|
1163
|
-
// where in this case, is the line(s) number(s) and not id(s)
|
|
1402
|
+
// "where" in this case, is the line(s) number(s) and not id(s)
|
|
1164
1403
|
const pathesContents = Object.fromEntries(
|
|
1165
1404
|
Object.entries(
|
|
1166
1405
|
this.joinPathesContents(
|
|
1167
|
-
join(this.
|
|
1406
|
+
join(this.folder, this.database, tableName),
|
|
1168
1407
|
Utils.isArrayOfObjects(data)
|
|
1169
1408
|
? (data as Data[]).map((item) => ({
|
|
1170
1409
|
...item,
|
|
@@ -1185,60 +1424,87 @@ export default class Inibase {
|
|
|
1185
1424
|
);
|
|
1186
1425
|
for (const [path, content] of Object.entries(pathesContents))
|
|
1187
1426
|
await File.replace(path, content);
|
|
1427
|
+
if (returnPostedData) return this.get(tableName, where, options);
|
|
1188
1428
|
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1189
1429
|
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1190
1430
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1191
1431
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1192
|
-
|
|
1193
|
-
} else throw this.throwError("
|
|
1432
|
+
return this.put(tableName, data, lineNumbers);
|
|
1433
|
+
} else throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
1194
1434
|
}
|
|
1195
1435
|
|
|
1196
1436
|
public async delete(
|
|
1197
1437
|
tableName: string,
|
|
1198
|
-
where?: number | string | (number | string)[] | Criteria
|
|
1199
|
-
|
|
1200
|
-
|
|
1438
|
+
where?: number | string | (number | string)[] | Criteria,
|
|
1439
|
+
_id?: string | string[]
|
|
1440
|
+
): Promise<string | string[] | null> {
|
|
1441
|
+
const schema = await this.getTableSchema(tableName);
|
|
1201
1442
|
if (!schema) throw this.throwError("NO_SCHEMA", tableName);
|
|
1443
|
+
const idFilePath = join(this.folder, this.database, tableName, "id.inib");
|
|
1444
|
+
if (!(await File.isExists(idFilePath)))
|
|
1445
|
+
throw this.throwError("NO_ITEMS", tableName);
|
|
1202
1446
|
if (!where) {
|
|
1203
|
-
const files =
|
|
1447
|
+
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1204
1448
|
if (files.length) {
|
|
1205
1449
|
for (const file in files.filter(
|
|
1206
|
-
(fileName: string) => fileName !== "schema
|
|
1450
|
+
(fileName: string) => fileName !== "schema"
|
|
1207
1451
|
))
|
|
1208
|
-
|
|
1452
|
+
await unlink(join(this.folder, this.database, tableName, file));
|
|
1209
1453
|
}
|
|
1210
|
-
|
|
1454
|
+
return "*";
|
|
1455
|
+
} else if (Utils.isValidID(where)) {
|
|
1211
1456
|
let Ids = where as string | string[];
|
|
1212
1457
|
if (!Array.isArray(Ids)) Ids = [Ids];
|
|
1213
|
-
const idFilePath = join(this.databasePath, tableName, "id.inib");
|
|
1214
|
-
if (!existsSync(idFilePath)) throw this.throwError("NO_ITEMS", tableName);
|
|
1215
1458
|
const [lineNumbers, countItems] = await File.search(
|
|
1216
1459
|
idFilePath,
|
|
1217
|
-
"number",
|
|
1218
1460
|
"[]",
|
|
1219
|
-
Ids.map((id) =>
|
|
1461
|
+
Ids.map((id) => UtilsServer.decodeID(id, this.salt)),
|
|
1462
|
+
undefined,
|
|
1463
|
+
"number",
|
|
1220
1464
|
undefined,
|
|
1221
|
-
Ids.length
|
|
1465
|
+
Ids.length,
|
|
1466
|
+
0,
|
|
1467
|
+
false,
|
|
1468
|
+
this.salt
|
|
1222
1469
|
);
|
|
1223
1470
|
if (!lineNumbers || !Object.keys(lineNumbers).length)
|
|
1224
1471
|
throw this.throwError("INVALID_ID");
|
|
1225
|
-
|
|
1472
|
+
return this.delete(
|
|
1473
|
+
tableName,
|
|
1474
|
+
Object.keys(lineNumbers).map(Number),
|
|
1475
|
+
where as string | string[]
|
|
1476
|
+
);
|
|
1226
1477
|
} else if (Utils.isNumber(where)) {
|
|
1227
|
-
const files =
|
|
1478
|
+
const files = await readdir(join(this.folder, this.database, tableName));
|
|
1228
1479
|
if (files.length) {
|
|
1229
|
-
|
|
1230
|
-
|
|
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"
|
|
1231
1495
|
))
|
|
1232
1496
|
await File.remove(
|
|
1233
|
-
join(this.
|
|
1497
|
+
join(this.folder, this.database, tableName, file),
|
|
1234
1498
|
where as number | number[]
|
|
1235
1499
|
);
|
|
1500
|
+
return Array.isArray(_id) && _id.length === 1 ? _id[0] : _id;
|
|
1236
1501
|
}
|
|
1237
1502
|
} else if (typeof where === "object" && !Array.isArray(where)) {
|
|
1238
1503
|
const lineNumbers = this.get(tableName, where, undefined, true);
|
|
1239
1504
|
if (!lineNumbers || !Array.isArray(lineNumbers) || !lineNumbers.length)
|
|
1240
1505
|
throw this.throwError("NO_ITEMS", tableName);
|
|
1241
|
-
|
|
1242
|
-
} else throw this.throwError("
|
|
1506
|
+
return this.delete(tableName, lineNumbers);
|
|
1507
|
+
} else throw this.throwError("INVALID_PARAMETERS", tableName);
|
|
1508
|
+
return null;
|
|
1243
1509
|
}
|
|
1244
1510
|
}
|