@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.
- package/dist/app/backup.js +24 -16
- package/dist/app/orm.d.ts +8 -7
- package/dist/app/orm.js +12 -7
- package/dist/app/table.d.ts +2 -2
- package/dist/app/table.js +9 -13
- package/dist/app/util.d.ts +3 -1
- package/dist/app/util.js +11 -2
- package/package.json +2 -2
- package/tests/test.js +7 -7
package/dist/app/backup.js
CHANGED
|
@@ -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,
|
|
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 ${
|
|
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
|
-
|
|
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 ${
|
|
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 ${
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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(
|
|
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.
|
|
109
|
-
}) ?? (await orm.
|
|
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
|
-
|
|
50
|
+
client: Knex<any, unknown[]>;
|
|
50
51
|
handler: Handler<Table<any>>;
|
|
51
|
-
_rawCache: ResponseCache<[
|
|
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
|
-
|
|
11
|
+
client;
|
|
12
12
|
handler;
|
|
13
13
|
_rawCache;
|
|
14
14
|
constructor(config) {
|
|
15
15
|
this.config = config;
|
|
16
|
-
this.
|
|
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
|
-
|
|
25
|
-
|
|
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.
|
|
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.
|
|
72
|
+
return this.client.raw(sql);
|
|
68
73
|
}
|
|
69
74
|
cache = {
|
|
70
75
|
raw: (sql, anyDataUpdated) => {
|
package/dist/app/table.d.ts
CHANGED
|
@@ -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,
|
|
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: <
|
|
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
|
|
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.
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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) {
|
package/dist/app/util.d.ts
CHANGED
|
@@ -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
|
|
2
|
-
import
|
|
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.
|
|
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": "^
|
|
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
|
-
.
|
|
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
|
-
.
|
|
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.
|
|
201
|
-
await orm.
|
|
202
|
-
await orm.
|
|
203
|
-
await orm.
|
|
204
|
-
await orm.
|
|
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
|
})
|