@ghom/orm 1.8.7 → 1.9.0

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.
@@ -1,24 +1,23 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import util from "util";
1
+ import fs from "node:fs";
2
+ import path from "node:path";
4
3
  import csv from "json-2-csv";
5
4
  import csvParser from "csv-parser";
6
- import { DEFAULT_BACKUP_CHUNK_SIZE, DEFAULT_BACKUP_LOCATION, DEFAULT_LOGGER_HIGHLIGHT, DEFAULT_LOGGER_RAW_VALUE, } from "./util.js";
5
+ import { DEFAULT_BACKUP_CHUNK_SIZE, DEFAULT_BACKUP_LOCATION, styled, } from "./util.js";
7
6
  export async function backupTable(table, dirname) {
8
7
  if (!table.orm)
9
8
  throw new Error("missing ORM");
10
9
  let offset = 0;
10
+ let processedRows = 0;
11
11
  let chunkIndex = 0;
12
12
  const chunkDir = path.join(table.orm.config.backups?.location ?? DEFAULT_BACKUP_LOCATION, dirname ?? "");
13
13
  if (!fs.existsSync(chunkDir)) {
14
14
  fs.mkdirSync(chunkDir, { recursive: true });
15
- console.log(`Backup directory ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, path.relative(process.cwd(), chunkDir))} created.`);
15
+ console.log(`Backup directory ${styled(table.orm, path.relative(process.cwd(), chunkDir), "highlight")} created.`);
16
16
  }
17
17
  try {
18
18
  // Compter le nombre total d'enregistrements dans la table
19
19
  const rowCount = await table.count();
20
20
  const limit = 1000; // Limite par requête
21
- const chunkCount = Math.ceil(rowCount / limit);
22
21
  let writeStream = null;
23
22
  const closePromises = []; // Tableau pour stocker les promesses de fermeture
24
23
  while (offset < rowCount) {
@@ -39,18 +38,21 @@ export async function backupTable(table, dirname) {
39
38
  }
40
39
  // Écrire les données dans le stream
41
40
  writeStream.write(csvData);
41
+ processedRows += rows.length;
42
42
  offset += limit;
43
- process.stdout.write(`\rBacking up table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)}: ${util.styleText(table.orm.config.loggerStyles?.rawValue ?? DEFAULT_LOGGER_RAW_VALUE, String(Math.round((chunkIndex / chunkCount) * 100)))}%`);
43
+ // Calcul du pourcentage basé sur le nombre de lignes traitées
44
+ const percentage = Math.round((processedRows / rowCount) * 100);
45
+ process.stdout.write(`\rBacking up table ${styled(table.orm, table.options.name, "highlight")}: ${styled(table.orm, String(percentage), "rawValue")}%`);
44
46
  }
45
47
  if (writeStream) {
46
48
  closePromises.push(new Promise((resolve) => writeStream.end(resolve))); // Ajouter la promesse de fermeture pour le dernier stream
47
49
  }
48
50
  // Attendre que tous les flux d'écriture soient fermés
49
51
  await Promise.all(closePromises);
50
- console.log(`\nBackup of table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)} completed.`);
52
+ console.log(`\nBackup of table ${styled(table.orm, table.options.name, "highlight")} completed.`);
51
53
  }
52
54
  catch (error) {
53
- console.error(`\nError while backing up table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)}:`, error);
55
+ console.error(`\nError while backing up table ${styled(table.orm, table.options.name, "highlight")}:`, error);
54
56
  }
55
57
  }
56
58
  export async function restoreBackup(table, trx, dirname) {
@@ -63,14 +65,19 @@ export async function restoreBackup(table, trx, dirname) {
63
65
  await trx(table.options.name).del();
64
66
  try {
65
67
  const limit = 1000; // Limite par requête
68
+ const totalChunks = chunkFiles.length;
69
+ let processedChunks = 0;
70
+ let totalRowsRestored = 0;
66
71
  for (let chunkFile of chunkFiles) {
67
72
  const filePath = path.join(chunkDir, chunkFile);
68
73
  let rows = [];
74
+ let chunkRowsCount = 0;
69
75
  await new Promise((resolve, reject) => {
70
76
  fs.createReadStream(filePath)
71
77
  .pipe(csvParser())
72
78
  .on("data", async (row) => {
73
79
  rows.push(row);
80
+ chunkRowsCount++;
74
81
  if (rows.length > limit) {
75
82
  const rowsCopy = rows.slice();
76
83
  rows = [];
@@ -81,19 +88,20 @@ export async function restoreBackup(table, trx, dirname) {
81
88
  // Insérer les données dans la table une fois le fichier entièrement lu
82
89
  if (rows.length > 0)
83
90
  await trx(table.options.name).insert(rows);
84
- console.log(`Restored chunk ${util.styleText(table.orm.config.loggerStyles?.highlight ??
85
- DEFAULT_LOGGER_HIGHLIGHT, chunkFile)} into table ${util.styleText(table.orm.config.loggerStyles?.highlight ??
86
- DEFAULT_LOGGER_HIGHLIGHT, table.options.name)}.`);
91
+ processedChunks++;
92
+ totalRowsRestored += chunkRowsCount;
93
+ const percentage = Math.round((processedChunks / totalChunks) * 100);
94
+ process.stdout.write(`\rRestoring table ${styled(table.orm, table.options.name, "highlight")}: ${styled(table.orm, String(percentage), "rawValue")}%`);
87
95
  resolve();
88
96
  })
89
97
  .on("error", reject);
90
98
  });
91
99
  }
100
+ console.log(`\nBackup of table ${styled(table.orm, table.options.name, "highlight")} restored. Total rows: ${styled(table.orm, String(totalRowsRestored), "rawValue")}`);
92
101
  }
93
102
  catch (error) {
94
- console.error(`Error while restoring backup of table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)}:`, error);
103
+ console.error(`\nError while restoring backup of table ${styled(table.orm, table.options.name, "highlight")}:`, error);
95
104
  }
96
- console.log(`Backup of table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)} restored.`);
97
105
  }
98
106
  export async function enableForeignKeys(orm, trx) {
99
107
  const ctx = trx ?? orm;
@@ -105,8 +113,8 @@ export async function enableForeignKeys(orm, trx) {
105
113
  }
106
114
  export async function disableForeignKeys(orm, run) {
107
115
  const trx = orm.clientBasedOperation({
108
- sqlite3: () => orm.database,
109
- }) ?? (await orm.database.transaction());
116
+ sqlite3: () => orm.client,
117
+ }) ?? (await orm.client.transaction());
110
118
  const ran = await orm.clientBasedOperation({
111
119
  mysql2: async () => {
112
120
  const result = await trx.raw("SELECT @@FOREIGN_KEY_CHECKS;");
package/dist/app/orm.d.ts CHANGED
@@ -8,6 +8,11 @@ export interface ILogger {
8
8
  error: (error: string | Error) => void;
9
9
  warn: (warning: string) => void;
10
10
  }
11
+ export interface LoggerStyles {
12
+ highlight: TextStyle;
13
+ rawValue: TextStyle;
14
+ description: TextStyle;
15
+ }
11
16
  export interface ORMConfig {
12
17
  /**
13
18
  * path to the directory that contains js files of tables
@@ -25,11 +30,7 @@ export interface ORMConfig {
25
30
  * Pattern used on logs when the table files are loaded or created. <br>
26
31
  * Based on node:util.styleText style names.
27
32
  */
28
- loggerStyles?: {
29
- highlight: TextStyle;
30
- rawValue: TextStyle;
31
- description: TextStyle;
32
- };
33
+ loggerStyles?: LoggerStyles;
33
34
  /**
34
35
  * Configuration for the database backups.
35
36
  */
@@ -46,9 +47,9 @@ export interface ORMConfig {
46
47
  export declare class ORM {
47
48
  config: ORMConfig;
48
49
  private _ready;
49
- database: Knex;
50
+ client: Knex<any, unknown[]>;
50
51
  handler: Handler<Table<any>>;
51
- _rawCache: ResponseCache<[sql: string], Knex.Raw>;
52
+ _rawCache: ResponseCache<[raw: string], Knex.Raw<any>>;
52
53
  constructor(config: ORMConfig);
53
54
  get cachedTables(): Table<any>[];
54
55
  get cachedTableNames(): string[];
package/dist/app/orm.js CHANGED
@@ -1,4 +1,4 @@
1
- import url from "url";
1
+ import url from "node:url";
2
2
  import { Handler } from "@ghom/handler";
3
3
  import { default as knex } from "knex";
4
4
  import { isCJS } from "./util.js";
@@ -8,12 +8,12 @@ import { backupTable, restoreBackup, disableForeignKeys, enableForeignKeys, } fr
8
8
  export class ORM {
9
9
  config;
10
10
  _ready = false;
11
- database;
11
+ client;
12
12
  handler;
13
13
  _rawCache;
14
14
  constructor(config) {
15
15
  this.config = config;
16
- this.database = knex(config.database ?? {
16
+ this.client = knex(config.database ?? {
17
17
  client: "sqlite3",
18
18
  useNullAsDefault: true,
19
19
  connection: {
@@ -21,8 +21,13 @@ export class ORM {
21
21
  },
22
22
  });
23
23
  this.handler = new Handler(config.tableLocation, {
24
- loader: (filepath) => import(isCJS ? filepath : url.pathToFileURL(filepath).href).then((file) => file.default),
25
- pattern: /\.js$/,
24
+ pattern: /\.[jt]s$/,
25
+ loader: async (filepath) => {
26
+ const file = await import(isCJS ? filepath : url.pathToFileURL(filepath).href);
27
+ if (file.default instanceof Table)
28
+ return file.default;
29
+ throw new Error(`${filepath}: default export must be a Table instance`);
30
+ },
26
31
  });
27
32
  this._rawCache = new ResponseCache((raw) => this.raw(raw), config.caching ?? Infinity);
28
33
  }
@@ -36,7 +41,7 @@ export class ORM {
36
41
  return this.cachedTables.some((table) => table.options.name === name);
37
42
  }
38
43
  async hasTable(name) {
39
- return this.database.schema.hasTable(name);
44
+ return this.client.schema.hasTable(name);
40
45
  }
41
46
  /**
42
47
  * Handle the table files and create the tables in the database.
@@ -64,7 +69,7 @@ export class ORM {
64
69
  raw(sql) {
65
70
  if (this._ready)
66
71
  this.cache.invalidate();
67
- return this.database.raw(sql);
72
+ return this.client.raw(sql);
68
73
  }
69
74
  cache = {
70
75
  raw: (sql, anyDataUpdated) => {
@@ -28,7 +28,7 @@ export declare class Table<Type extends object = object> {
28
28
  ], unknown>;
29
29
  _countCache?: ResponseCache<[where: string | null], Promise<number>>;
30
30
  constructor(options: TableOptions<Type>);
31
- get db(): Knex<any, any[]>;
31
+ get db(): Knex<any, unknown[]>;
32
32
  get query(): Knex.QueryBuilder<Type, {
33
33
  _base: Type;
34
34
  _hasSelection: false;
@@ -40,7 +40,7 @@ export declare class Table<Type extends object = object> {
40
40
  }[]>;
41
41
  get cache(): {
42
42
  get: <Return>(id: string, cb: (table: Pick<Table<Type>["query"], "select" | "count" | "avg" | "sum" | "countDistinct" | "avgDistinct" | "sumDistinct">) => Return) => Return;
43
- set: <Return_1>(cb: (table: Pick<Table<Type>["query"], "update" | "delete" | "insert" | "upsert" | "truncate" | "jsonInsert">) => Return_1) => Return_1;
43
+ set: <Return>(cb: (table: Pick<Table<Type>["query"], "update" | "delete" | "insert" | "upsert" | "truncate" | "jsonInsert">) => Return) => Return;
44
44
  count: (where?: string) => Promise<number>;
45
45
  invalidate: () => void;
46
46
  };
package/dist/app/table.js CHANGED
@@ -1,6 +1,5 @@
1
- import util from "util";
1
+ import { styled } from "./util.js";
2
2
  import { ResponseCache } from "./caching.js";
3
- import { DEFAULT_LOGGER_DESCRIPTION, DEFAULT_LOGGER_HIGHLIGHT, DEFAULT_LOGGER_RAW_VALUE, } from "./util.js";
4
3
  export class Table {
5
4
  options;
6
5
  orm;
@@ -12,7 +11,7 @@ export class Table {
12
11
  get db() {
13
12
  if (!this.orm)
14
13
  throw new Error("missing ORM");
15
- return this.orm.database;
14
+ return this.orm.client;
16
15
  }
17
16
  get query() {
18
17
  return this.db(this.options.name);
@@ -66,29 +65,26 @@ export class Table {
66
65
  this.orm = orm;
67
66
  this._whereCache = new ResponseCache((cb) => cb(this.query), this.options.caching ?? this.orm?.config.caching ?? Infinity);
68
67
  this._countCache = new ResponseCache((where) => this.count(where ?? undefined), this.options.caching ?? this.orm?.config.caching ?? Infinity);
68
+ const tableNameLog = `table ${styled(this.orm, this.options.name, "highlight")}${this.options.description
69
+ ? ` ${styled(this.orm, this.options.description, "description")}`
70
+ : ""}`;
69
71
  try {
70
72
  await this.db.schema.createTable(this.options.name, this.options.setup);
71
- this.orm.config.logger?.log(`created table ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)}${this.options.description
72
- ? ` ${util.styleText(this.orm.config.loggerStyles?.description ??
73
- DEFAULT_LOGGER_DESCRIPTION, this.options.description)}`
74
- : ""}`);
73
+ this.orm.config.logger?.log(`created table ${tableNameLog}`);
75
74
  }
76
75
  catch (error) {
77
76
  if (error.toString().includes("syntax error")) {
78
- this.orm.config.logger?.error(`you need to implement the "setup" method in options of your ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)} table!`);
77
+ this.orm.config.logger?.error(`you need to implement the "setup" method in options of your ${styled(this.orm, this.options.name, "highlight")} table!`);
79
78
  throw error;
80
79
  }
81
80
  else {
82
- this.orm.config.logger?.log(`loaded table ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)}${this.options.description
83
- ? ` ${util.styleText(this.orm.config.loggerStyles?.description ??
84
- DEFAULT_LOGGER_DESCRIPTION, this.options.description)}`
85
- : ""}`);
81
+ this.orm.config.logger?.log(`loaded table ${tableNameLog}`);
86
82
  }
87
83
  }
88
84
  try {
89
85
  const migrated = await this.migrate();
90
86
  if (migrated !== false) {
91
- this.orm.config.logger?.log(`migrated table ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)} to version ${util.styleText(this.orm.config.loggerStyles?.rawValue ?? DEFAULT_LOGGER_RAW_VALUE, String(migrated))}`);
87
+ this.orm.config.logger?.log(`migrated table ${styled(this.orm, this.options.name, "highlight")} to version ${styled(this.orm, migrated, "rawValue")}`);
92
88
  }
93
89
  }
94
90
  catch (error) {
@@ -1,4 +1,5 @@
1
- import util from "util";
1
+ import util from "node:util";
2
+ import type { LoggerStyles, ORM } from "./orm.js";
2
3
  export type TextStyle = Parameters<typeof util.styleText>[0];
3
4
  export declare const DEFAULT_BACKUP_LOCATION: string;
4
5
  export declare const DEFAULT_BACKUP_CHUNK_SIZE: number;
@@ -7,3 +8,4 @@ export declare const DEFAULT_LOGGER_DESCRIPTION = "grey";
7
8
  export declare const DEFAULT_LOGGER_RAW_VALUE = "magentaBright";
8
9
  declare let isCJS: boolean;
9
10
  export { isCJS };
11
+ export declare function styled(orm: ORM, message: string | boolean | number, style: keyof LoggerStyles): string;
package/dist/app/util.js CHANGED
@@ -1,5 +1,6 @@
1
- import path from "path";
2
- import fs from "fs";
1
+ import util from "node:util";
2
+ import path from "node:path";
3
+ import fs from "node:fs";
3
4
  export const DEFAULT_BACKUP_LOCATION = path.join(process.cwd(), "backup");
4
5
  export const DEFAULT_BACKUP_CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
5
6
  export const DEFAULT_LOGGER_HIGHLIGHT = "blueBright";
@@ -16,3 +17,11 @@ catch {
16
17
  "Please create a package.json file or run the project from another entry point.");
17
18
  }
18
19
  export { isCJS };
20
+ export function styled(orm, message, style) {
21
+ return util.styleText(orm.config.loggerStyles?.[style] ??
22
+ (style === "highlight"
23
+ ? DEFAULT_LOGGER_HIGHLIGHT
24
+ : style === "rawValue"
25
+ ? DEFAULT_LOGGER_RAW_VALUE
26
+ : DEFAULT_LOGGER_DESCRIPTION), String(message));
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghom/orm",
3
- "version": "1.8.7",
3
+ "version": "1.9.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "sqlite3": "^5.1.6"
32
32
  },
33
33
  "dependencies": {
34
- "@ghom/handler": "^2.0.0",
34
+ "@ghom/handler": "^3.1.0",
35
35
  "csv-parser": "^3.0.0",
36
36
  "json-2-csv": "^5.5.6",
37
37
  "knex": "^3.0.1"
package/tests/test.js CHANGED
@@ -61,7 +61,7 @@ describe("table column types", () => {
61
61
  test("increments", async () => {
62
62
  expect(
63
63
  await orm
64
- .database("a")
64
+ .client("a")
65
65
  .columnInfo("id")
66
66
  .then((info) => info.type),
67
67
  ).toMatch(/^int/)
@@ -70,7 +70,7 @@ describe("table column types", () => {
70
70
  test("integer", async () => {
71
71
  expect(
72
72
  await orm
73
- .database("a")
73
+ .client("a")
74
74
  .columnInfo("b_id")
75
75
  .then((info) => info.type),
76
76
  ).toMatch(/^int/)
@@ -197,9 +197,9 @@ describe("data caching", () => {
197
197
  })
198
198
 
199
199
  afterAll(async () => {
200
- await orm.database.schema.dropTable("migration")
201
- await orm.database.schema.dropTable("a")
202
- await orm.database.schema.dropTable("b")
203
- await orm.database.schema.dropTable("c")
204
- await orm.database.destroy()
200
+ await orm.client.schema.dropTable("migration")
201
+ await orm.client.schema.dropTable("a")
202
+ await orm.client.schema.dropTable("b")
203
+ await orm.client.schema.dropTable("c")
204
+ await orm.client.destroy()
205
205
  })