inibase 1.0.0-rc.75 → 1.0.0-rc.76

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 CHANGED
@@ -632,11 +632,11 @@ import Inibase from "inibase";
632
632
  const db = new Inibase("/databaseName");
633
633
 
634
634
  // order users by the age column
635
- await db.sort("user", "age");
635
+ await db.get("user", undefined, { sort: "age" });
636
636
 
637
637
  // order users by the age and username columns
638
- await db.sort("user", ["age","username"]);
639
- await db.sort("user", {age: -1, username: "asc"});
638
+ await db.get("user", undefined, { sort: ["age", "username"] });
639
+ await db.get("user", undefined, { sort: {age: -1, username: "asc"} });
640
640
  ```
641
641
  </blockquote>
642
642
  </details>
package/dist/cli.js CHANGED
@@ -196,7 +196,7 @@ rl.on("line", async (input) => {
196
196
  console.log(`${textRed(" Err:")} Please specify table name`);
197
197
  break;
198
198
  }
199
- let where = undefined, page = undefined, perPage = undefined, columns = undefined, data = undefined;
199
+ let where = undefined, page = undefined, perPage = undefined, columns = undefined, sort = undefined, data = undefined;
200
200
  if (splitedInput.toSpliced(0, 1).length) {
201
201
  const parsedArgs = parseArgs({
202
202
  args: splitedInput.toSpliced(0, table ? 1 : 2),
@@ -204,6 +204,7 @@ rl.on("line", async (input) => {
204
204
  where: { type: "string", short: "w" },
205
205
  page: { type: "string", short: "p" },
206
206
  perPage: { type: "string", short: "l" },
207
+ sort: { type: "string", short: "s" },
207
208
  columns: { type: "string", short: "c", multiple: true },
208
209
  data: { type: "string", short: "d" },
209
210
  },
@@ -216,6 +217,12 @@ rl.on("line", async (input) => {
216
217
  else if (isJSON(parsedArgs.where))
217
218
  where = Inison.unstringify(parsedArgs.where);
218
219
  }
220
+ if (parsedArgs.sort) {
221
+ if (isJSON(parsedArgs.sort))
222
+ sort = Inison.unstringify(parsedArgs.sort);
223
+ else
224
+ sort = parsedArgs.sort;
225
+ }
219
226
  page = Number(parsedArgs.page) ?? undefined;
220
227
  perPage = Number(parsedArgs.perPage) ?? undefined;
221
228
  columns = parsedArgs.columns;
@@ -229,6 +236,7 @@ rl.on("line", async (input) => {
229
236
  page: Number(page) ?? 1,
230
237
  perPage: Number(perPage) ?? 15,
231
238
  columns,
239
+ sort,
232
240
  }));
233
241
  break;
234
242
  case "p":
package/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@ export interface Options {
21
21
  page?: number;
22
22
  perPage?: number;
23
23
  columns?: string[] | string;
24
- order?: Record<string, "asc" | "desc">;
24
+ sort?: Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC"> | string[] | string;
25
25
  }
26
26
  export interface Config {
27
27
  compression?: boolean;
@@ -113,13 +113,14 @@ export default class Inibase {
113
113
  * @param {string} tableName
114
114
  * @param {(string | number | (string | number)[] | Criteria | undefined)} [where]
115
115
  * @param {(Options | undefined)} [options]
116
- * @param {true} [onlyOne]
117
- * @param {undefined} [onlyLinesNumbers]
118
- * @param {boolean} [_skipIdColumn]
116
+ * @param {boolean} [onlyOne]
117
+ * @param {boolean} [onlyLinesNumbers]
119
118
  * @return {*} {(Promise<Data[] | Data | number[] | null>)}
120
119
  */
121
- get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: true, onlyLinesNumbers?: undefined, _skipIdColumn?: boolean): Promise<Data | null>;
122
- get(tableName: string, where?: string | number | (string | number)[] | Criteria | undefined, options?: Options | undefined, onlyOne?: boolean | undefined, onlyLinesNumbers?: true, _skipIdColumn?: boolean): Promise<number[]>;
120
+ get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: true, onlyLinesNumbers?: false): Promise<Data | null>;
121
+ get(tableName: string, where: string | number, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data | null>;
122
+ get(tableName: string, where?: string | number | (string | number)[] | Criteria, options?: Options, onlyOne?: boolean, onlyLinesNumbers?: false): Promise<Data[] | null>;
123
+ get(tableName: string, where: string | number | (string | number)[] | Criteria | undefined, options: Options | undefined, onlyOne: boolean | undefined, onlyLinesNumbers: true): Promise<number[]>;
123
124
  /**
124
125
  * Create new item(s) in a table
125
126
  *
@@ -183,18 +184,4 @@ export default class Inibase {
183
184
  */
184
185
  min(tableName: string, columns: string, where?: number | string | (number | string)[] | Criteria): Promise<number>;
185
186
  min(tableName: string, columns: string[], where?: number | string | (number | string)[] | Criteria): Promise<Record<string, number>>;
186
- /**
187
- * Sort column(s) of a table
188
- *
189
- * @param {string} tableName
190
- * @param {(string
191
- * | string[]
192
- * | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
193
- * @param {(string | number | (string | number)[] | Criteria)} [where]
194
- * @param {Options} [options={
195
- * page: 1,
196
- * perPage: 15,
197
- * }]
198
- */
199
- sort(tableName: string, columns: string | string[] | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">, where?: string | number | (string | number)[] | Criteria, options?: Options): Promise<any[]>;
200
187
  }
package/dist/index.js CHANGED
@@ -794,16 +794,14 @@ export default class Inibase {
794
794
  async get(tableName, where, options = {
795
795
  page: 1,
796
796
  perPage: 15,
797
- }, onlyOne, onlyLinesNumbers, _skipIdColumn) {
797
+ }, onlyOne, onlyLinesNumbers) {
798
798
  const tablePath = join(this.databasePath, tableName);
799
799
  // Ensure options.columns is an array
800
800
  if (options.columns) {
801
801
  options.columns = Array.isArray(options.columns)
802
802
  ? options.columns
803
803
  : [options.columns];
804
- if (!_skipIdColumn &&
805
- options.columns.length &&
806
- !options.columns.includes("id"))
804
+ if (options.columns.length && !options.columns.includes("id"))
807
805
  options.columns.push("id");
808
806
  }
809
807
  // Default values for page and perPage
@@ -821,6 +819,96 @@ export default class Inibase {
821
819
  ((Array.isArray(where) && !where.length) ||
822
820
  (Utils.isObject(where) && !Object.keys(where).length)))
823
821
  where = undefined;
822
+ if (options.sort) {
823
+ let sortArray, isLineNumbers = true, keepItems = [];
824
+ if (Utils.isObject(options.sort) && !Array.isArray(options.sort)) {
825
+ // {name: "ASC", age: "DESC"}
826
+ sortArray = Object.entries(options.sort).map(([key, value]) => [
827
+ key,
828
+ typeof value === "string" ? value.toLowerCase() === "asc" : value > 0,
829
+ ]);
830
+ }
831
+ else
832
+ sortArray = []
833
+ .concat(options.sort)
834
+ .map((column) => [column, true]);
835
+ let cacheKey = "";
836
+ // Criteria
837
+ if (this.tables[tableName].config.cache)
838
+ cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
839
+ if (where) {
840
+ const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
841
+ keepItems = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
842
+ isLineNumbers = false;
843
+ if (!keepItems.length)
844
+ throw this.throwError("NO_RESULTS", tableName);
845
+ keepItems = keepItems.slice((options.page - 1) * options.perPage, options.page * options.perPage);
846
+ }
847
+ if (!keepItems.length)
848
+ keepItems = Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
849
+ index +
850
+ 1);
851
+ const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}${this.getFileExtension(tableName)}`));
852
+ for await (const path of filesPathes.slice(1))
853
+ if (!(await File.isExists(path)))
854
+ return null;
855
+ // Construct the paste command to merge files and filter lines by IDs
856
+ const pasteCommand = `paste ${filesPathes.join(" ")}`;
857
+ // Construct the sort command dynamically based on the number of files for sorting
858
+ const index = 2;
859
+ const sortColumns = sortArray
860
+ .map(([key, ascending], i) => {
861
+ const field = Utils.getField(key, schema);
862
+ if (field)
863
+ return `-k${i + index},${i + index}${Utils.isFieldType(["id", "number", "date"], field.type, field.children)
864
+ ? "n"
865
+ : ""}${!ascending ? "r" : ""}`;
866
+ return "";
867
+ })
868
+ .join(" ");
869
+ const sortCommand = `sort ${sortColumns} -T=${join(tablePath, ".tmp")}`;
870
+ // Construct the awk command to keep only the specified lines after sorting
871
+ const awkCommand = isLineNumbers
872
+ ? `awk '${keepItems.map((lineNumber) => `NR==${lineNumber}`).join(" || ")}'`
873
+ : `awk '${keepItems.map((id) => `$1 ~ /^${id} */`).join(" || ")}'`;
874
+ try {
875
+ if (cacheKey)
876
+ await File.lock(join(tablePath, ".tmp"), cacheKey);
877
+ // Combine && Execute the commands synchronously
878
+ const lines = (await UtilsServer.exec(this.tables[tableName].config.cache
879
+ ? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
880
+ ? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
881
+ : `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
882
+ : `${pasteCommand} | ${sortCommand} | ${awkCommand}`, {
883
+ encoding: "utf-8",
884
+ })).stdout
885
+ .trim()
886
+ .split("\n");
887
+ // Parse the result and extract the specified lines
888
+ const outputArray = lines.map((line) => {
889
+ const splitedFileColumns = line.split("\t"); // Assuming tab-separated columns
890
+ const outputObject = {};
891
+ // Extract values for each file, including `id${this.getFileExtension(tableName)}`
892
+ filesPathes.forEach((fileName, index) => {
893
+ const field = Utils.getField(parse(fileName).name, schema);
894
+ if (field)
895
+ outputObject[field.key] = File.decode(splitedFileColumns[index], field?.type, field?.children, this.salt);
896
+ });
897
+ return outputObject;
898
+ });
899
+ const restOfColumns = await this.get(tableName, outputArray.map(({ id }) => id), (({ sort, ...rest }) => rest)(options));
900
+ return restOfColumns
901
+ ? outputArray.map((item) => ({
902
+ ...item,
903
+ ...restOfColumns.find(({ id }) => id === item.id),
904
+ }))
905
+ : outputArray;
906
+ }
907
+ finally {
908
+ if (cacheKey)
909
+ await File.unlock(join(tablePath, ".tmp"), cacheKey);
910
+ }
911
+ }
824
912
  if (!where) {
825
913
  // Display all data
826
914
  RETURN = Object.values(await this.getItemsFromSchema(tableName, schema, Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
@@ -861,6 +949,11 @@ export default class Inibase {
861
949
  return Object.keys(lineNumbers).length
862
950
  ? Object.keys(lineNumbers).map(Number)
863
951
  : null;
952
+ if (options.columns) {
953
+ options.columns = options.columns.filter((column) => column !== "id");
954
+ if (!options.columns?.length)
955
+ options.columns = undefined;
956
+ }
864
957
  RETURN = Object.values((await this.getItemsFromSchema(tableName, schema, Object.keys(lineNumbers).map(Number), options)) ?? {});
865
958
  if (!this.totalItems[`${tableName}-*`])
866
959
  this.totalItems[`${tableName}-*`] = countItems;
@@ -1214,113 +1307,4 @@ export default class Inibase {
1214
1307
  }
1215
1308
  return RETURN;
1216
1309
  }
1217
- /**
1218
- * Sort column(s) of a table
1219
- *
1220
- * @param {string} tableName
1221
- * @param {(string
1222
- * | string[]
1223
- * | Record<string, 1 | -1 | "asc" | "ASC" | "desc" | "DESC">)} columns
1224
- * @param {(string | number | (string | number)[] | Criteria)} [where]
1225
- * @param {Options} [options={
1226
- * page: 1,
1227
- * perPage: 15,
1228
- * }]
1229
- */
1230
- async sort(tableName, columns, where, options = {
1231
- page: 1,
1232
- perPage: 15,
1233
- }) {
1234
- const tablePath = join(this.databasePath, tableName), schema = (await this.throwErrorIfTableEmpty(tableName)).schema;
1235
- // Default values for page and perPage
1236
- options.page = options.page || 1;
1237
- options.perPage = options.perPage || 15;
1238
- let sortArray, isLineNumbers = true, keepItems = [];
1239
- if (Utils.isObject(columns) && !Array.isArray(columns)) {
1240
- // {name: "ASC", age: "DESC"}
1241
- sortArray = Object.entries(columns).map(([key, value]) => [
1242
- key,
1243
- typeof value === "string" ? value.toLowerCase() === "asc" : value > 0,
1244
- ]);
1245
- }
1246
- else {
1247
- if (!Array.isArray(columns))
1248
- columns = [columns];
1249
- sortArray = columns.map((column) => [column, true]);
1250
- }
1251
- let cacheKey = "";
1252
- // Criteria
1253
- if (this.tables[tableName].config.cache)
1254
- cacheKey = UtilsServer.hashString(inspect(sortArray, { sorted: true }));
1255
- if (where) {
1256
- const lineNumbers = await this.get(tableName, where, undefined, undefined, true);
1257
- keepItems = Object.values((await File.get(join(tablePath, `id${this.getFileExtension(tableName)}`), lineNumbers, "number", undefined, this.salt)) ?? {}).map(Number);
1258
- isLineNumbers = false;
1259
- if (!keepItems.length)
1260
- throw this.throwError("NO_RESULTS", tableName);
1261
- keepItems = keepItems.slice((options.page - 1) * options.perPage, options.page * options.perPage);
1262
- }
1263
- if (!keepItems.length)
1264
- keepItems = Array.from({ length: options.perPage }, (_, index) => (options.page - 1) * options.perPage +
1265
- index +
1266
- 1);
1267
- const filesPathes = [["id", true], ...sortArray].map((column) => join(tablePath, `${column[0]}${this.getFileExtension(tableName)}`));
1268
- // Construct the paste command to merge files and filter lines by IDs
1269
- const pasteCommand = `paste ${filesPathes.join(" ")}`;
1270
- // Construct the sort command dynamically based on the number of files for sorting
1271
- const index = 2;
1272
- const sortColumns = sortArray
1273
- .map(([key, ascending], i) => {
1274
- const field = Utils.getField(key, schema);
1275
- if (field)
1276
- return `-k${i + index},${i + index}${field.type === "number" ? "n" : ""}${!ascending ? "r" : ""}`;
1277
- return "";
1278
- })
1279
- .join(" ");
1280
- const sortCommand = `sort ${sortColumns}`;
1281
- // Construct the awk command to keep only the specified lines after sorting
1282
- const awkCommand = isLineNumbers
1283
- ? `awk '${keepItems.map((line) => `NR==${line}`).join(" || ")}'`
1284
- : `awk 'NR==${keepItems[0]}${keepItems
1285
- .map((num) => `||NR==${num}`)
1286
- .join("")}'`;
1287
- try {
1288
- if (cacheKey)
1289
- await File.lock(join(tablePath, ".tmp"), cacheKey);
1290
- // Combine the commands
1291
- // Execute the command synchronously
1292
- const lines = (await UtilsServer.exec(this.tables[tableName].config.cache
1293
- ? (await File.isExists(join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)))
1294
- ? `${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
1295
- : `${pasteCommand} | ${sortCommand} -o ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)} && ${awkCommand} ${join(tablePath, ".cache", `${cacheKey}${this.fileExtension}`)}`
1296
- : `${pasteCommand} | ${sortCommand} | ${awkCommand}`, {
1297
- encoding: "utf-8",
1298
- })).stdout
1299
- .trim()
1300
- .split("\n");
1301
- // Parse the result and extract the specified lines
1302
- const outputArray = lines.map((line) => {
1303
- const splitedFileColumns = line.split("\t"); // Assuming tab-separated columns
1304
- const outputObject = {};
1305
- // Extract values for each file, including `id${this.getFileExtension(tableName)}`
1306
- filesPathes.forEach((fileName, index) => {
1307
- const field = Utils.getField(parse(fileName).name, schema);
1308
- if (field)
1309
- outputObject[field.key] = File.decode(splitedFileColumns[index], field?.type, field?.children, this.salt);
1310
- });
1311
- return outputObject;
1312
- });
1313
- const restOfColumns = await this.get(tableName, outputArray.map(({ id }) => id), options, undefined, undefined, true);
1314
- return restOfColumns
1315
- ? outputArray.map((item, index) => ({
1316
- ...item,
1317
- ...restOfColumns[index],
1318
- }))
1319
- : outputArray;
1320
- }
1321
- finally {
1322
- if (cacheKey)
1323
- await File.unlock(join(tablePath, ".tmp"), cacheKey);
1324
- }
1325
- }
1326
1310
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inibase",
3
- "version": "1.0.0-rc.75",
3
+ "version": "1.0.0-rc.76",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Karim Amahtil",