inibase 1.0.0-rc.10 → 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.
Files changed (4) hide show
  1. package/file.ts +112 -69
  2. package/index.test.ts +44 -3
  3. package/index.ts +28 -12
  4. package/package.json +1 -1
package/file.ts CHANGED
@@ -20,6 +20,8 @@ export const isExists = async (path: string) => {
20
20
  }
21
21
  };
22
22
 
23
+ const delimiters = [",", "|", "&", "$", "#", "@", "^", "%", ":", "!", ";"];
24
+
23
25
  export const encode = (
24
26
  input:
25
27
  | string
@@ -30,23 +32,42 @@ export const encode = (
30
32
  secretKey?: string | Buffer
31
33
  ) => {
32
34
  const secureString = (input: string | number | boolean | null) => {
33
- if (["true", "false"].includes(String(input))) return input ? 1 : 0;
34
- return typeof input === "string"
35
- ? decodeURIComponent(input)
36
- .replaceAll("<", "&lt;")
37
- .replaceAll(">", "&gt;")
38
- .replaceAll(",", "%2C")
39
- .replaceAll("|", "%7C")
40
- .replaceAll("\n", "\\n")
41
- .replaceAll("\r", "\\r")
42
- : input;
43
- };
35
+ if (["true", "false"].includes(String(input))) return input ? 1 : 0;
36
+ return typeof input === "string"
37
+ ? decodeURIComponent(input)
38
+ .replaceAll("<", "&lt;")
39
+ .replaceAll(">", "&gt;")
40
+ .replaceAll(",", "%2C")
41
+ .replaceAll("|", "%7C")
42
+ .replaceAll("&", "%26")
43
+ .replaceAll("$", "%24")
44
+ .replaceAll("#", "%23")
45
+ .replaceAll("@", "%40")
46
+ .replaceAll("^", "%5E")
47
+ .replaceAll("%", "%25")
48
+ .replaceAll(":", "%3A")
49
+ .replaceAll("!", "%21")
50
+ .replaceAll(";", "%3B")
51
+ .replaceAll("\n", "\\n")
52
+ .replaceAll("\r", "\\r")
53
+ : input;
54
+ },
55
+ secureArray = (arr_str: any[] | any): any[] | any =>
56
+ Array.isArray(arr_str) ? arr_str.map(secureArray) : secureString(arr_str),
57
+ joinMultidimensionalArray = (
58
+ arr: any[] | any[][],
59
+ delimiter_index = 0
60
+ ): string => {
61
+ delimiter_index++;
62
+ if (isArrayOfArrays(arr))
63
+ arr = arr.map((ar: any[]) =>
64
+ joinMultidimensionalArray(ar, delimiter_index)
65
+ );
66
+ delimiter_index--;
67
+ return arr.join(delimiters[delimiter_index]);
68
+ };
44
69
  return Array.isArray(input)
45
- ? isArrayOfArrays(input)
46
- ? (input as any[])
47
- .map((_input) => _input.map(secureString).join(","))
48
- .join("|")
49
- : input.map(secureString).join(",")
70
+ ? joinMultidimensionalArray(secureArray(input))
50
71
  : secureString(input);
51
72
  };
52
73
 
@@ -58,65 +79,87 @@ export const decode = (
58
79
  ): string | number | boolean | null | (string | number | null | boolean)[] => {
59
80
  if (!fieldType) return null;
60
81
  const unSecureString = (input: string) =>
61
- decodeURIComponent(input)
62
- .replaceAll("&lt;", "<")
63
- .replaceAll("&gt;", ">")
64
- .replaceAll("%2C", ",")
65
- .replaceAll("%7C", "|")
66
- .replaceAll("\\n", "\n")
67
- .replaceAll("\\r", "\r") || null;
82
+ decodeURIComponent(input)
83
+ .replaceAll("&lt;", "<")
84
+ .replaceAll("&gt;", ">")
85
+ .replaceAll("%2C", ",")
86
+ .replaceAll("%7C", "|")
87
+ .replaceAll("%26", "&")
88
+ .replaceAll("%24", "$")
89
+ .replaceAll("%23", "#")
90
+ .replaceAll("%40", "@")
91
+ .replaceAll("%5E", "^")
92
+ .replaceAll("%25", "%")
93
+ .replaceAll("%3A", ":")
94
+ .replaceAll("%21", "!")
95
+ .replaceAll("%3B", ";")
96
+ .replaceAll("\\n", "\n")
97
+ .replaceAll("\\r", "\r") || null,
98
+ unSecureArray = (arr_str: any[] | any): any[] | any =>
99
+ Array.isArray(arr_str)
100
+ ? arr_str.map(unSecureArray)
101
+ : unSecureString(arr_str),
102
+ reverseJoinMultidimensionalArray = (
103
+ joinedString: string | any[] | any[][]
104
+ ): any | any[] | any[][] => {
105
+ const reverseJoinMultidimensionalArrayHelper = (
106
+ arr: any | any[] | any[][],
107
+ delimiter: string
108
+ ) =>
109
+ Array.isArray(arr)
110
+ ? arr.map((ar: any) =>
111
+ reverseJoinMultidimensionalArrayHelper(ar, delimiter)
112
+ )
113
+ : arr.split(delimiter);
114
+
115
+ const availableDelimiters = delimiters.filter((delimiter) =>
116
+ joinedString.includes(delimiter)
117
+ );
118
+ for (const delimiter of availableDelimiters) {
119
+ joinedString = Array.isArray(joinedString)
120
+ ? reverseJoinMultidimensionalArrayHelper(joinedString, delimiter)
121
+ : joinedString.split(delimiter);
122
+ }
123
+ return joinedString;
124
+ },
125
+ decodeHelper = (value: string | number | any[]) => {
126
+ if (Array.isArray(value) && fieldType !== "array")
127
+ return value.map(decodeHelper);
128
+ switch (fieldType as FieldType) {
129
+ case "table":
130
+ case "number":
131
+ return isNumber(value) ? Number(value) : null;
132
+ case "boolean":
133
+ return typeof value === "string" ? value === "true" : Boolean(value);
134
+ case "array":
135
+ if (!Array.isArray(value)) return [value];
136
+
137
+ if (fieldChildrenType)
138
+ return value.map(
139
+ (v) =>
140
+ decode(
141
+ v,
142
+ Array.isArray(fieldChildrenType)
143
+ ? detectFieldType(v, fieldChildrenType)
144
+ : fieldChildrenType,
145
+ undefined,
146
+ secretKey
147
+ ) as string | number | boolean | null
148
+ );
149
+ else return value;
150
+ case "id":
151
+ return isNumber(value) ? encodeID(value as number, secretKey) : value;
152
+ default:
153
+ return value;
154
+ }
155
+ };
68
156
  if (input === null || input === "") return null;
69
157
  if (Array.isArray(fieldType))
70
158
  fieldType = detectFieldType(String(input), fieldType);
71
- const decodeHelper = (value: string | number | any[]) => {
72
- if (Array.isArray(value) && fieldType !== "array")
73
- return value.map(decodeHelper);
74
- switch (fieldType as FieldType) {
75
- case "table":
76
- case "number":
77
- return isNumber(value) ? Number(value) : null;
78
- case "boolean":
79
- return typeof value === "string" ? value === "true" : Boolean(value);
80
- case "array":
81
- if (!Array.isArray(value)) return [value];
82
-
83
- if (fieldChildrenType)
84
- return value.map(
85
- (v) =>
86
- decode(
87
- v,
88
- Array.isArray(fieldChildrenType)
89
- ? detectFieldType(v, fieldChildrenType)
90
- : fieldChildrenType,
91
- undefined,
92
- secretKey
93
- ) as string | number | boolean | null
94
- );
95
- else return value;
96
- case "id":
97
- return isNumber(value) ? encodeID(value as number, secretKey) : value;
98
- default:
99
- return value;
100
- }
101
- };
102
159
  return decodeHelper(
103
160
  typeof input === "string"
104
161
  ? input.includes(",")
105
- ? input.includes("|")
106
- ? input
107
- .split("|")
108
- .map((_input) => _input.split(",").map(unSecureString))
109
- : input.split(",").map(unSecureString)
110
- : input.includes("|")
111
- ? input
112
- .split("|")
113
- .map((_input) => [
114
- _input
115
- ? fieldType === "array"
116
- ? [unSecureString(_input)]
117
- : unSecureString(_input)
118
- : null,
119
- ])
162
+ ? unSecureArray(reverseJoinMultidimensionalArray(input))
120
163
  : unSecureString(input)
121
164
  : input
122
165
  );
package/index.test.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { decode } from "./file";
1
2
  import Inibase, { Schema, Data } from "./index";
2
3
  import { join } from "node:path";
3
4
  // import os from "os";
@@ -197,9 +198,49 @@ const data_2 = [
197
198
  try {
198
199
  // db.setTableSchema("database", schema_2);
199
200
  // const DATA = await db.post("database", data_2);
200
- const DATA = await db.get("user", {
201
- or: { username: "admin", email: "demo" },
202
- });
201
+ // const DATA = await db.delete("database", 2);
202
+ // const DATA = await db.post("database", {
203
+ // slug: "demo",
204
+ // tables: [
205
+ // {
206
+ // id: 1,
207
+ // slug: "user",
208
+ // allowed_methods: [
209
+ // {
210
+ // role: "user",
211
+ // methods: ["c", "r", "u"],
212
+ // },
213
+ // {
214
+ // role: "guest",
215
+ // methods: ["c"],
216
+ // },
217
+ // {
218
+ // role: "admin",
219
+ // methods: ["d", "u"],
220
+ // },
221
+ // ],
222
+ // },
223
+ // {
224
+ // id: 1,
225
+ // slug: "user",
226
+ // allowed_methods: [
227
+ // {
228
+ // role: "user",
229
+ // methods: ["c", "r", "u"],
230
+ // },
231
+ // {
232
+ // role: "guest",
233
+ // methods: ["c"],
234
+ // },
235
+ // {
236
+ // role: "admin",
237
+ // methods: ["d", "u"],
238
+ // },
239
+ // ],
240
+ // },
241
+ // ],
242
+ // });
243
+ const DATA = await db.get("database");
203
244
  console.log(JSON.stringify(DATA, null, 4));
204
245
  } catch (er) {
205
246
  console.log(er);
package/index.ts CHANGED
@@ -609,12 +609,13 @@ export default class Inibase {
609
609
  (prefix ?? "") + key + "."
610
610
  )
611
611
  );
612
- else
612
+ else {
613
613
  RETURN[(prefix ?? "") + key] = File.encode(value) as
614
614
  | boolean
615
615
  | number
616
616
  | string
617
617
  | null;
618
+ }
618
619
  } else
619
620
  RETURN[(prefix ?? "") + key] = File.encode(value) as
620
621
  | boolean
@@ -635,6 +636,20 @@ export default class Inibase {
635
636
  return addPathToKeys(CombineData(data), mainPath);
636
637
  }
637
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
+
638
653
  public async get(
639
654
  tableName: string,
640
655
  where?: string | number | (string | number)[] | Criteria,
@@ -1269,7 +1284,7 @@ export default class Inibase {
1269
1284
  let last_id = (await File.isExists(idFilePath))
1270
1285
  ? Number(
1271
1286
  Object.values(
1272
- await File.get(idFilePath, -1, "number", undefined, this.salt)
1287
+ (await File.get(idFilePath, -1, "number", undefined, this.salt))[0]
1273
1288
  )[0]
1274
1289
  )
1275
1290
  : 0;
@@ -1289,6 +1304,7 @@ export default class Inibase {
1289
1304
  created_at: new Date(),
1290
1305
  }))(data as Data);
1291
1306
  if (!RETURN) throw this.throwError("NO_DATA");
1307
+
1292
1308
  RETURN = this.formatData(RETURN, schema);
1293
1309
  const pathesContents = this.joinPathesContents(
1294
1310
  join(this.folder, this.database, tableName),
@@ -1463,16 +1479,16 @@ export default class Inibase {
1463
1479
  if (files.length) {
1464
1480
  if (!_id)
1465
1481
  _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));
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));
1476
1492
  for (const file of files.filter(
1477
1493
  (fileName: string) =>
1478
1494
  fileName.endsWith(".inib") && fileName !== "schema"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.10",
3
+ "version": "1.0.0-rc.11",
4
4
  "description": "File-based Relational Database for large data",
5
5
  "main": "index.ts",
6
6
  "type": "module",