@ghom/orm 1.7.2 → 1.8.1

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.
@@ -0,0 +1,40 @@
1
+ # This is a basic workflow to help you get started with Actions
2
+
3
+ name: Test
4
+
5
+ # Controls when the action will run.
6
+ on:
7
+ # Triggers the workflow on push or pull request events but only for the master branch
8
+ push:
9
+ branches: [ master ]
10
+ pull_request:
11
+ branches: [ master ]
12
+
13
+ # Allows you to run this workflow manually from the Actions tab
14
+ workflow_dispatch:
15
+
16
+ # A workflow run is made up of one or more jobs that can run sequentially or in parallel
17
+ jobs:
18
+ # This workflow contains a single job called "build"
19
+ test:
20
+ # The type of runner that the job will run on
21
+ runs-on: ubuntu-latest
22
+
23
+ # Steps represent a sequence of tasks that will be executed as part of the job
24
+ steps:
25
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
26
+ - uses: actions/checkout@v2
27
+
28
+ - name: Setup Node
29
+ uses: actions/setup-node@v3
30
+ with:
31
+ node-version: 22
32
+
33
+ - name: Install dependencies
34
+ run: npm install
35
+
36
+ - name: Build the source
37
+ run: npm run build
38
+
39
+ - name: Start the tests
40
+ run: npm run test
@@ -0,0 +1,22 @@
1
+ <component name="ProjectRunConfigurationManager">
2
+ <configuration default="false" name="All Tests" type="JavaScriptTestRunnerJest" nameIsGenerated="true">
3
+ <node-interpreter value="project" />
4
+ <node-options value="--experimental-vm-modules" />
5
+ <jest-package value="$PROJECT_DIR$/node_modules/jest" />
6
+ <working-dir value="$PROJECT_DIR$" />
7
+ <jest-options value="tests/test.js --detectOpenHandles" />
8
+ <envs />
9
+ <scope-kind value="ALL" />
10
+ <method v="2">
11
+ <option name="NpmBeforeRunTask" enabled="true">
12
+ <package-json value="$PROJECT_DIR$/package.json" />
13
+ <command value="run" />
14
+ <scripts>
15
+ <script value="build" />
16
+ </scripts>
17
+ <node-interpreter value="project" />
18
+ <envs />
19
+ </option>
20
+ </method>
21
+ </configuration>
22
+ </component>
@@ -0,0 +1,6 @@
1
+ import { ORM } from "./orm.js";
2
+ import { Table } from "./table.js";
3
+ export declare function backupTable(table: Table, dirname?: string): Promise<void>;
4
+ export declare function restoreBackup(table: Table, dirname?: string): Promise<void>;
5
+ export declare function disableForeignKeys(orm: ORM): Promise<void>;
6
+ export declare function enableForeignKeys(orm: ORM): Promise<void>;
@@ -0,0 +1,119 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import util from "util";
4
+ import csv from "json-2-csv";
5
+ import csvParser from "csv-parser";
6
+ import { DEFAULT_BACKUP_CHUNK_SIZE, DEFAULT_BACKUP_LOCATION, DEFAULT_LOGGER_HIGHLIGHT, DEFAULT_LOGGER_RAW_VALUE, } from "./util.js";
7
+ export async function backupTable(table, dirname) {
8
+ if (!table.orm)
9
+ throw new Error("missing ORM");
10
+ let offset = 0;
11
+ let chunkIndex = 0;
12
+ const chunkDir = path.join(table.orm.config.backups?.location ?? DEFAULT_BACKUP_LOCATION, dirname ?? "");
13
+ if (!fs.existsSync(chunkDir)) {
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.`);
16
+ }
17
+ try {
18
+ // Compter le nombre total d'enregistrements dans la table
19
+ const rowCount = await table.count();
20
+ const limit = 1000; // Limite par requête
21
+ const chunkCount = Math.ceil(rowCount / limit);
22
+ let writeStream = null;
23
+ const closePromises = []; // Tableau pour stocker les promesses de fermeture
24
+ while (offset < rowCount) {
25
+ // Récupérer un "chunk" de données
26
+ const rows = await table.query.select("*").limit(limit).offset(offset);
27
+ // Convertir les données en CSV
28
+ const csvData = csv.json2csv(rows);
29
+ // Si aucun fichier n'est créé ou qu'on a dépassé la taille max du chunk, on crée un nouveau fichier CSV
30
+ if (!writeStream ||
31
+ writeStream.bytesWritten + Buffer.byteLength(csvData, "utf8") >
32
+ (table.orm.config.backups?.chunkSize ?? DEFAULT_BACKUP_CHUNK_SIZE)) {
33
+ if (writeStream) {
34
+ closePromises.push(new Promise((resolve) => writeStream.end(resolve))); // Ajouter la promesse de fermeture
35
+ }
36
+ const chunkFile = path.join(chunkDir, `${table.options.name}_chunk_${chunkIndex}.csv`);
37
+ writeStream = fs.createWriteStream(chunkFile, { flags: "a" });
38
+ chunkIndex++;
39
+ }
40
+ // Écrire les données dans le stream
41
+ writeStream.write(csvData);
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)))}%`);
44
+ }
45
+ if (writeStream) {
46
+ closePromises.push(new Promise((resolve) => writeStream.end(resolve))); // Ajouter la promesse de fermeture pour le dernier stream
47
+ }
48
+ // Attendre que tous les flux d'écriture soient fermés
49
+ await Promise.all(closePromises);
50
+ console.log(`\nBackup of table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)} completed.`);
51
+ }
52
+ catch (error) {
53
+ console.error(`\nError while backing up table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)}:`, error);
54
+ }
55
+ }
56
+ export async function restoreBackup(table, dirname) {
57
+ if (!table.orm)
58
+ throw new Error("missing ORM");
59
+ const chunkDir = path.join(table.orm.config.backups?.location ?? DEFAULT_BACKUP_LOCATION, dirname ?? "");
60
+ const chunkFiles = fs
61
+ .readdirSync(chunkDir)
62
+ .filter((file) => file.split("_chunk_")[0] === table.options.name);
63
+ await table.query.truncate();
64
+ try {
65
+ const limit = 1000; // Limite par requête
66
+ for (let chunkFile of chunkFiles) {
67
+ const filePath = path.join(chunkDir, chunkFile);
68
+ let rows = [];
69
+ await new Promise((resolve, reject) => {
70
+ fs.createReadStream(filePath)
71
+ .pipe(csvParser())
72
+ .on("data", async (row) => {
73
+ rows.push(row);
74
+ if (rows.length > limit) {
75
+ const rowsCopy = rows.slice();
76
+ rows = [];
77
+ await table.query.insert(rowsCopy);
78
+ }
79
+ })
80
+ .on("end", async () => {
81
+ // Insérer les données dans la table une fois le fichier entièrement lu
82
+ if (rows.length > 0)
83
+ await table.query.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)}.`);
87
+ resolve();
88
+ })
89
+ .on("error", reject);
90
+ });
91
+ }
92
+ }
93
+ 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);
95
+ }
96
+ console.log(`Backup of table ${util.styleText(table.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, table.options.name)} restored.`);
97
+ }
98
+ export async function disableForeignKeys(orm) {
99
+ const result = await Promise.allSettled([
100
+ orm.raw("SET session_replication_role = replica;"),
101
+ orm.raw("PRAGMA foreign_keys = OFF;"),
102
+ orm.raw("SET FOREIGN_KEY_CHECKS = 0;"), // for mysql2
103
+ ]);
104
+ const errors = result.filter((r) => r.status === "rejected");
105
+ if (errors.length === 3) {
106
+ throw new Error("Failed to disable foreign key constraints.");
107
+ }
108
+ }
109
+ export async function enableForeignKeys(orm) {
110
+ const result = await Promise.allSettled([
111
+ orm.raw("SET session_replication_role = DEFAULT;"),
112
+ orm.raw("PRAGMA foreign_keys = ON;"),
113
+ orm.raw("SET FOREIGN_KEY_CHECKS = 1;"), // for mysql2
114
+ ]);
115
+ const errors = result.filter((r) => r.status === "rejected");
116
+ if (errors.length === 3) {
117
+ throw new Error("Failed to enable foreign key constraints.");
118
+ }
119
+ }
@@ -0,0 +1,18 @@
1
+ export interface ResponseCacheData<Value> {
2
+ value: Value;
3
+ expires: number;
4
+ outdated?: boolean;
5
+ }
6
+ /**
7
+ * Advanced cache for async queries
8
+ */
9
+ export declare class ResponseCache<Params extends any[], Value> {
10
+ private _request;
11
+ private _timeout;
12
+ private _cache;
13
+ constructor(_request: (...params: Params) => Value, _timeout: number);
14
+ get(id: string, ...params: Params): Value;
15
+ fetch(id: string, ...params: Params): Value;
16
+ invalidate(): void;
17
+ invalidate(id: string): void;
18
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Advanced cache for async queries
3
+ */
4
+ export class ResponseCache {
5
+ _request;
6
+ _timeout;
7
+ _cache = new Map();
8
+ constructor(_request, _timeout) {
9
+ this._request = _request;
10
+ this._timeout = _timeout;
11
+ }
12
+ get(id, ...params) {
13
+ const cached = this._cache.get(id);
14
+ if (!cached || cached.expires < Date.now()) {
15
+ this._cache.set(id, {
16
+ value: this._request(...params),
17
+ expires: Date.now() + this._timeout,
18
+ });
19
+ }
20
+ return this._cache.get(id).value;
21
+ }
22
+ fetch(id, ...params) {
23
+ this._cache.set(id, {
24
+ value: this._request(...params),
25
+ expires: Date.now() + this._timeout,
26
+ });
27
+ return this._cache.get(id).value;
28
+ }
29
+ invalidate(id) {
30
+ if (!id) {
31
+ this._cache.clear();
32
+ return;
33
+ }
34
+ this._cache.delete(id);
35
+ }
36
+ }
@@ -1,7 +1,8 @@
1
1
  import { Handler } from "@ghom/handler";
2
2
  import { Knex } from "knex";
3
+ import { TextStyle } from "./util.js";
3
4
  import { Table } from "./table.js";
4
- import { Color } from "chalk";
5
+ import { ResponseCache } from "./caching";
5
6
  export interface ILogger {
6
7
  log: (message: string) => void;
7
8
  error: (error: string | Error) => void;
@@ -11,7 +12,7 @@ export interface ORMConfig {
11
12
  /**
12
13
  * path to the directory that contains js files of tables
13
14
  */
14
- location: string;
15
+ tableLocation: string;
15
16
  /**
16
17
  * database configuration
17
18
  */
@@ -22,18 +23,32 @@ export interface ORMConfig {
22
23
  logger?: ILogger;
23
24
  /**
24
25
  * Pattern used on logs when the table files are loaded or created. <br>
25
- * Based on Chalk color-method names.
26
+ * Based on node:util.styleText style names.
26
27
  */
27
- loggerColors?: {
28
- highlight: typeof Color;
29
- rawValue: typeof Color;
30
- description: typeof Color;
28
+ loggerStyles?: {
29
+ highlight: TextStyle;
30
+ rawValue: TextStyle;
31
+ description: TextStyle;
31
32
  };
33
+ /**
34
+ * Configuration for the database backups.
35
+ */
36
+ backups?: {
37
+ location?: string;
38
+ chunkSize?: number;
39
+ };
40
+ /**
41
+ * The cache time in milliseconds. <br>
42
+ * Default is `Infinity`.
43
+ */
44
+ caching?: number;
32
45
  }
33
46
  export declare class ORM {
34
47
  config: ORMConfig;
48
+ private _ready;
35
49
  database: Knex;
36
50
  handler: Handler<Table<any>>;
51
+ _rawCache: ResponseCache<[sql: string], Knex.Raw>;
37
52
  constructor(config: ORMConfig);
38
53
  get cachedTables(): Table<any>[];
39
54
  get cachedTableNames(): string[];
@@ -44,4 +59,18 @@ export declare class ORM {
44
59
  */
45
60
  init(): Promise<void>;
46
61
  raw(sql: Knex.Value): Knex.Raw;
62
+ cache: {
63
+ raw: (sql: string, anyDataUpdated?: boolean) => Knex.Raw;
64
+ invalidate: () => void;
65
+ };
66
+ /**
67
+ * Create a backup of the database. <br>
68
+ * The backup will be saved in the location specified in the config.
69
+ */
70
+ createBackup(dirname?: string): Promise<void>;
71
+ /**
72
+ * Restore the database from the backup. <br>
73
+ * @warning This will delete all the data in the tables.
74
+ */
75
+ restoreBackup(dirname?: string): Promise<void>;
47
76
  }
@@ -0,0 +1,109 @@
1
+ import url from "url";
2
+ import { Handler } from "@ghom/handler";
3
+ import { default as knex } from "knex";
4
+ import { isCJS } from "./util.js";
5
+ import { Table } from "./table.js";
6
+ import { backupTable, restoreBackup, disableForeignKeys, enableForeignKeys, } from "./backup.js";
7
+ import { ResponseCache } from "./caching";
8
+ export class ORM {
9
+ config;
10
+ _ready = false;
11
+ database;
12
+ handler;
13
+ _rawCache;
14
+ constructor(config) {
15
+ this.config = config;
16
+ this.database = knex(config.database ?? {
17
+ client: "sqlite3",
18
+ useNullAsDefault: true,
19
+ connection: {
20
+ filename: ":memory:",
21
+ },
22
+ });
23
+ this.handler = new Handler(config.tableLocation, {
24
+ loader: (filepath) => import(isCJS ? filepath : url.pathToFileURL(filepath).href).then((file) => file.default),
25
+ pattern: /\.js$/,
26
+ });
27
+ this._rawCache = new ResponseCache((raw) => this.raw(raw), config.caching ?? Infinity);
28
+ }
29
+ get cachedTables() {
30
+ return [...this.handler.elements.values()];
31
+ }
32
+ get cachedTableNames() {
33
+ return this.cachedTables.map((table) => table.options.name);
34
+ }
35
+ hasCachedTable(name) {
36
+ return this.cachedTables.some((table) => table.options.name === name);
37
+ }
38
+ async hasTable(name) {
39
+ return this.database.schema.hasTable(name);
40
+ }
41
+ /**
42
+ * Handle the table files and create the tables in the database.
43
+ */
44
+ async init() {
45
+ await this.handler.init();
46
+ await enableForeignKeys(this);
47
+ this.handler.elements.set("migration", new Table({
48
+ name: "migration",
49
+ priority: Infinity,
50
+ setup: (table) => {
51
+ table.string("table").unique().notNullable();
52
+ table.integer("version").notNullable();
53
+ },
54
+ }));
55
+ for (const table of this.cachedTables.sort((a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0))) {
56
+ table.orm = this;
57
+ await table.make();
58
+ }
59
+ this._ready = true;
60
+ }
61
+ raw(sql) {
62
+ if (this._ready)
63
+ this.cache.invalidate();
64
+ return this.database.raw(sql);
65
+ }
66
+ cache = {
67
+ raw: (sql, anyDataUpdated) => {
68
+ if (anyDataUpdated)
69
+ this.cache.invalidate();
70
+ return this._rawCache.get(sql, sql);
71
+ },
72
+ invalidate: () => {
73
+ this._rawCache.invalidate();
74
+ this.cachedTables.forEach((table) => table.cache.invalidate());
75
+ },
76
+ };
77
+ /**
78
+ * Create a backup of the database. <br>
79
+ * The backup will be saved in the location specified in the config.
80
+ */
81
+ async createBackup(dirname) {
82
+ try {
83
+ for (let table of this.cachedTables) {
84
+ await backupTable(table, dirname);
85
+ }
86
+ console.log("Database backup created.");
87
+ }
88
+ catch (error) {
89
+ console.error("Error while creating backup of the database.", error);
90
+ }
91
+ }
92
+ /**
93
+ * Restore the database from the backup. <br>
94
+ * @warning This will delete all the data in the tables.
95
+ */
96
+ async restoreBackup(dirname) {
97
+ try {
98
+ await disableForeignKeys(this);
99
+ for (let table of this.cachedTables) {
100
+ await restoreBackup(table, dirname);
101
+ }
102
+ await enableForeignKeys(this);
103
+ console.log("Database restored from backup.");
104
+ }
105
+ catch (error) {
106
+ console.error("Error while restoring backup of the database.", error);
107
+ }
108
+ }
109
+ }
@@ -1,5 +1,6 @@
1
1
  import { Knex } from "knex";
2
2
  import { ORM } from "./orm.js";
3
+ import { ResponseCache } from "./caching.js";
3
4
  export interface MigrationData {
4
5
  table: string;
5
6
  version: number;
@@ -8,6 +9,11 @@ export interface TableOptions<Type extends object = object> {
8
9
  name: string;
9
10
  description?: string;
10
11
  priority?: number;
12
+ /**
13
+ * The cache time in milliseconds. <br>
14
+ * Default is `Infinity`.
15
+ */
16
+ caching?: number;
11
17
  migrations?: {
12
18
  [version: number]: (table: Knex.CreateTableBuilder) => void;
13
19
  };
@@ -17,6 +23,10 @@ export interface TableOptions<Type extends object = object> {
17
23
  export declare class Table<Type extends object = object> {
18
24
  readonly options: TableOptions<Type>;
19
25
  orm?: ORM;
26
+ _whereCache?: ResponseCache<[
27
+ cb: (query: Table<Type>["query"]) => unknown
28
+ ], unknown>;
29
+ _countCache?: ResponseCache<[where: string | null], Promise<number>>;
20
30
  constructor(options: TableOptions<Type>);
21
31
  get db(): Knex<any, any[]>;
22
32
  get query(): Knex.QueryBuilder<Type, {
@@ -28,6 +38,12 @@ export declare class Table<Type extends object = object> {
28
38
  _intersectProps: {};
29
39
  _unionProps: never;
30
40
  }[]>;
41
+ get cache(): {
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;
44
+ count: (where?: string) => Promise<number>;
45
+ invalidate: () => void;
46
+ };
31
47
  count(where?: string): Promise<number>;
32
48
  hasColumn(name: keyof Type & string): Promise<boolean>;
33
49
  getColumn(name: keyof Type & string): Promise<Knex.ColumnInfo>;
@@ -1,7 +1,11 @@
1
- import chalk from "chalk";
1
+ import util from "util";
2
+ import { ResponseCache } from "./caching.js";
3
+ import { DEFAULT_LOGGER_DESCRIPTION, DEFAULT_LOGGER_HIGHLIGHT, DEFAULT_LOGGER_RAW_VALUE, } from "./util.js";
2
4
  export class Table {
3
5
  options;
4
6
  orm;
7
+ _whereCache;
8
+ _countCache;
5
9
  constructor(options) {
6
10
  this.options = options;
7
11
  }
@@ -13,6 +17,30 @@ export class Table {
13
17
  get query() {
14
18
  return this.db(this.options.name);
15
19
  }
20
+ get cache() {
21
+ if (!this._whereCache || !this._countCache)
22
+ throw new Error("missing cache");
23
+ if (!this.orm)
24
+ throw new Error("missing ORM");
25
+ return {
26
+ get: (id, cb) => {
27
+ return this._whereCache.get(id, cb);
28
+ },
29
+ set: (cb) => {
30
+ // todo: invalidate only the related tables
31
+ this.orm.cache.invalidate();
32
+ return cb(this.query);
33
+ },
34
+ count: (where) => {
35
+ return this._countCache.get(where ?? "*", where ?? null);
36
+ },
37
+ invalidate: () => {
38
+ this._whereCache.invalidate();
39
+ this._countCache.invalidate();
40
+ this.orm._rawCache.invalidate();
41
+ },
42
+ };
43
+ }
16
44
  async count(where) {
17
45
  return this.query
18
46
  .select(this.db.raw("count(*) as total"))
@@ -32,32 +60,36 @@ export class Table {
32
60
  return this.getColumns().then(Object.keys);
33
61
  }
34
62
  async isEmpty() {
35
- return this.count().then((count) => count === 0);
63
+ return this.count().then((count) => +count === 0);
36
64
  }
37
65
  async make() {
38
66
  if (!this.orm)
39
67
  throw new Error("missing ORM");
68
+ this._whereCache = new ResponseCache((cb) => cb(this.query), this.options.caching ?? this.orm?.config.caching ?? Infinity);
69
+ this._countCache = new ResponseCache((where) => this.count(where ?? undefined), this.options.caching ?? this.orm?.config.caching ?? Infinity);
40
70
  try {
41
71
  await this.db.schema.createTable(this.options.name, this.options.setup);
42
- this.orm.config.logger?.log(`created table ${chalk[this.orm.config.loggerColors?.highlight ?? "blueBright"](this.options.name)}${this.options.description
43
- ? ` ${chalk[this.orm.config.loggerColors?.description ?? "grey"](this.options.description)}`
72
+ this.orm.config.logger?.log(`created table ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)}${this.options.description
73
+ ? ` ${util.styleText(this.orm.config.loggerStyles?.description ??
74
+ DEFAULT_LOGGER_DESCRIPTION, this.options.description)}`
44
75
  : ""}`);
45
76
  }
46
77
  catch (error) {
47
78
  if (error.toString().includes("syntax error")) {
48
- this.orm.config.logger?.error(`you need to implement the "setup" method in options of your ${chalk[this.orm.config.loggerColors?.highlight ?? "blueBright"](this.options.name)} table!`);
79
+ 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!`);
49
80
  throw error;
50
81
  }
51
82
  else {
52
- this.orm.config.logger?.log(`loaded table ${chalk[this.orm.config.loggerColors?.highlight ?? "blueBright"](this.options.name)}${this.options.description
53
- ? ` ${chalk[this.orm.config.loggerColors?.description ?? "grey"](this.options.description)}`
83
+ this.orm.config.logger?.log(`loaded table ${util.styleText(this.orm.config.loggerStyles?.highlight ?? DEFAULT_LOGGER_HIGHLIGHT, this.options.name)}${this.options.description
84
+ ? ` ${util.styleText(this.orm.config.loggerStyles?.description ??
85
+ DEFAULT_LOGGER_DESCRIPTION, this.options.description)}`
54
86
  : ""}`);
55
87
  }
56
88
  }
57
89
  try {
58
90
  const migrated = await this.migrate();
59
91
  if (migrated !== false) {
60
- this.orm.config.logger?.log(`migrated table ${chalk[this.orm.config.loggerColors?.highlight ?? "blueBright"](this.options.name)} to version ${chalk[this.orm.config.loggerColors?.rawValue ?? "magentaBright"](migrated)}`);
92
+ 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))}`);
61
93
  }
62
94
  }
63
95
  catch (error) {
@@ -0,0 +1,9 @@
1
+ import util from "util";
2
+ export type TextStyle = Parameters<typeof util.styleText>[0];
3
+ export declare const DEFAULT_BACKUP_LOCATION: string;
4
+ export declare const DEFAULT_BACKUP_CHUNK_SIZE: number;
5
+ export declare const DEFAULT_LOGGER_HIGHLIGHT = "blueBright";
6
+ export declare const DEFAULT_LOGGER_DESCRIPTION = "grey";
7
+ export declare const DEFAULT_LOGGER_RAW_VALUE = "magentaBright";
8
+ declare let isCJS: boolean;
9
+ export { isCJS };
@@ -0,0 +1,18 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ export const DEFAULT_BACKUP_LOCATION = path.join(process.cwd(), "backup");
4
+ export const DEFAULT_BACKUP_CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
5
+ export const DEFAULT_LOGGER_HIGHLIGHT = "blueBright";
6
+ export const DEFAULT_LOGGER_DESCRIPTION = "grey";
7
+ export const DEFAULT_LOGGER_RAW_VALUE = "magentaBright";
8
+ let isCJS = false;
9
+ try {
10
+ const pack = JSON.parse(fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8"));
11
+ isCJS = pack.type === "commonjs" || pack.type == void 0;
12
+ }
13
+ catch {
14
+ throw new Error("Missing package.json: Can't detect the type of modules.\n" +
15
+ "The ORM needs a package.json file present in the process's current working directory.\n" +
16
+ "Please create a package.json file or run the project from another entry point.");
17
+ }
18
+ export { isCJS };
@@ -0,0 +1,5 @@
1
+ export * from "./app/orm.js";
2
+ export * from "./app/table.js";
3
+ export * from "./app/caching.js";
4
+ export * from "./app/backup.js";
5
+ export * from "./app/util.js";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./app/orm.js";
2
+ export * from "./app/table.js";
3
+ export * from "./app/caching.js";
4
+ export * from "./app/backup.js";
5
+ export * from "./app/util.js";
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@ghom/orm",
3
- "version": "1.7.2",
3
+ "version": "1.8.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "main": "dist/esm/index.js",
7
- "types": "dist/typings/index.d.ts",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
8
  "description": "TypeScript KnexJS ORM & handler",
9
+ "homepage": "https://github.com/GhomKrosmonaute/orm",
9
10
  "prettier": {
10
11
  "semi": false
11
12
  },
@@ -14,17 +15,18 @@
14
15
  "require": "./dist/cjs/index.js"
15
16
  },
16
17
  "scripts": {
17
- "format": "prettier --write src tsconfig.*",
18
- "build": "rm -fr dist/* && tsc -p tsconfig-esm.json && tsc -p tsconfig-cjs.json && fixup.sh",
18
+ "format": "prettier --write src tsconfig.json tests",
19
+ "build": "rimraf dist && tsc",
19
20
  "test": "npm run build && node --experimental-vm-modules node_modules/jest/bin/jest.js tests/test.js --detectOpenHandles",
20
21
  "prepublishOnly": "npm run format && npm test"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@types/jest": "^29.5.6",
24
- "@types/node": "^20.8.9",
25
+ "@types/node": "^22.0.0",
25
26
  "dotenv": "^16.3.1",
26
27
  "jest": "^29.7.0",
27
28
  "prettier": "^3.0.3",
29
+ "rimraf": "^6.0.1",
28
30
  "typescript": "^5.2.2"
29
31
  },
30
32
  "optionalDependencies": {
@@ -34,6 +36,15 @@
34
36
  },
35
37
  "dependencies": {
36
38
  "@ghom/handler": "^2.0.0",
39
+ "csv-parser": "^3.0.0",
40
+ "json-2-csv": "^5.5.6",
37
41
  "knex": "^3.0.1"
42
+ },
43
+ "engines": {
44
+ "node": ">=22.0.0"
45
+ },
46
+ "repository": {
47
+ "url": "https://github.com/GhomKrosmonaute/orm.git",
48
+ "type": "git"
38
49
  }
39
50
  }