@ghom/orm 1.9.2 → 2.0.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/orm.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Handler } from "@ghom/handler";
2
- import { Knex } from "knex";
3
- import { TextStyle } from "./util.js";
4
- import { Table } from "./table.js";
5
2
  import { CachedQuery } from "@ghom/query";
3
+ import { type Knex } from "knex";
4
+ import { Table } from "./table.js";
5
+ import { type TextStyle } from "./util.js";
6
6
  export interface ILogger {
7
7
  log: (message: string) => void;
8
8
  error: (error: string | Error) => void;
@@ -44,13 +44,47 @@ export interface ORMConfig {
44
44
  */
45
45
  caching?: number;
46
46
  }
47
+ /**
48
+ * The main ORM class that manages database connections, tables, and caching.
49
+ *
50
+ * @example
51
+ * // With database connection
52
+ * const orm = new ORM({
53
+ * tableLocation: "./tables",
54
+ * database: { client: "sqlite3", connection: { filename: ":memory:" } }
55
+ * })
56
+ * await orm.init()
57
+ *
58
+ * @example
59
+ * // Without database connection (for type exports only)
60
+ * const orm = new ORM(false)
61
+ * orm.isConnected // false
62
+ */
47
63
  export declare class ORM {
48
- config: ORMConfig;
64
+ config: ORMConfig | false;
49
65
  private _ready;
50
- client: Knex<any, unknown[]>;
51
- handler: Handler<Table<any>>;
52
- _rawCache: CachedQuery<[raw: string], any>;
53
- constructor(config: ORMConfig);
66
+ _client?: Knex;
67
+ handler?: Handler<Table<any>>;
68
+ _rawCache?: CachedQuery<[raw: string], Knex.Raw>;
69
+ /**
70
+ * Creates a new ORM instance.
71
+ *
72
+ * @param config - The ORM configuration, or `false` to create an unconnected instance.
73
+ *
74
+ * When `false` is passed, the ORM will not connect to any database.
75
+ * This is useful for scenarios where you only need to export types or
76
+ * use the ORM structure without an actual database connection.
77
+ *
78
+ * Methods that require a database connection will throw an error
79
+ * if called on an unconnected ORM instance.
80
+ */
81
+ constructor(config: ORMConfig | false);
82
+ private requireClient;
83
+ get client(): Knex;
84
+ /**
85
+ * Returns true if the ORM has a database client connected.
86
+ */
87
+ get isConnected(): boolean;
54
88
  get cachedTables(): Table<any>[];
55
89
  get cachedTableNames(): string[];
56
90
  hasCachedTable(name: string): boolean;
package/dist/app/orm.js CHANGED
@@ -1,19 +1,49 @@
1
1
  import url from "node:url";
2
2
  import { Handler } from "@ghom/handler";
3
+ import { CachedQuery } from "@ghom/query";
3
4
  import { default as knex } from "knex";
4
- import { isCJS } from "./util.js";
5
+ import { backupTable, disableForeignKeys, enableForeignKeys, restoreBackup } from "./backup.js";
5
6
  import { Table } from "./table.js";
6
- import { CachedQuery } from "@ghom/query";
7
- import { backupTable, restoreBackup, disableForeignKeys, enableForeignKeys, } from "./backup.js";
7
+ import { isCJS } from "./util.js";
8
+ /**
9
+ * The main ORM class that manages database connections, tables, and caching.
10
+ *
11
+ * @example
12
+ * // With database connection
13
+ * const orm = new ORM({
14
+ * tableLocation: "./tables",
15
+ * database: { client: "sqlite3", connection: { filename: ":memory:" } }
16
+ * })
17
+ * await orm.init()
18
+ *
19
+ * @example
20
+ * // Without database connection (for type exports only)
21
+ * const orm = new ORM(false)
22
+ * orm.isConnected // false
23
+ */
8
24
  export class ORM {
9
25
  config;
10
26
  _ready = false;
11
- client;
27
+ _client;
12
28
  handler;
13
29
  _rawCache;
30
+ /**
31
+ * Creates a new ORM instance.
32
+ *
33
+ * @param config - The ORM configuration, or `false` to create an unconnected instance.
34
+ *
35
+ * When `false` is passed, the ORM will not connect to any database.
36
+ * This is useful for scenarios where you only need to export types or
37
+ * use the ORM structure without an actual database connection.
38
+ *
39
+ * Methods that require a database connection will throw an error
40
+ * if called on an unconnected ORM instance.
41
+ */
14
42
  constructor(config) {
15
43
  this.config = config;
16
- this.client = knex(config.database ?? {
44
+ if (config === false)
45
+ return;
46
+ this._client = knex(config.database ?? {
17
47
  client: "sqlite3",
18
48
  useNullAsDefault: true,
19
49
  connection: {
@@ -31,7 +61,23 @@ export class ORM {
31
61
  });
32
62
  this._rawCache = new CachedQuery(async (raw) => await this.raw(raw), config.caching ?? Infinity);
33
63
  }
64
+ requireClient() {
65
+ if (!this._client)
66
+ throw new Error("ORM client is not initialized. Cannot use this method without a database connection.");
67
+ }
68
+ get client() {
69
+ this.requireClient();
70
+ return this._client;
71
+ }
72
+ /**
73
+ * Returns true if the ORM has a database client connected.
74
+ */
75
+ get isConnected() {
76
+ return this._client !== undefined;
77
+ }
34
78
  get cachedTables() {
79
+ if (!this.handler)
80
+ return [];
35
81
  return [...this.handler.elements.values()];
36
82
  }
37
83
  get cachedTableNames() {
@@ -41,12 +87,14 @@ export class ORM {
41
87
  return this.cachedTables.some((table) => table.options.name === name);
42
88
  }
43
89
  async hasTable(name) {
44
- return this.client.schema.hasTable(name);
90
+ this.requireClient();
91
+ return this._client.schema.hasTable(name);
45
92
  }
46
93
  /**
47
94
  * Handle the table files and create the tables in the database.
48
95
  */
49
96
  async init() {
97
+ this.requireClient();
50
98
  await this.handler.init();
51
99
  try {
52
100
  await enableForeignKeys(this);
@@ -55,10 +103,10 @@ export class ORM {
55
103
  this.handler.elements.set("migration", new Table({
56
104
  name: "migration",
57
105
  priority: Infinity,
58
- setup: (table) => {
59
- table.string("table").unique().notNullable();
60
- table.integer("version").notNullable();
61
- },
106
+ columns: (col) => ({
107
+ table: col.string().unique(),
108
+ version: col.integer(),
109
+ }),
62
110
  }));
63
111
  const sortedTables = this.cachedTables.toSorted((a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0));
64
112
  for (const table of sortedTables) {
@@ -67,22 +115,26 @@ export class ORM {
67
115
  this._ready = true;
68
116
  }
69
117
  raw(sql) {
118
+ this.requireClient();
70
119
  if (this._ready)
71
120
  this.cache.invalidate();
72
- return this.client.raw(sql);
121
+ return this._client.raw(sql);
73
122
  }
74
123
  cache = {
75
124
  raw: (sql, anyDataUpdated) => {
125
+ this.requireClient();
76
126
  if (anyDataUpdated)
77
127
  this.cache.invalidate();
78
128
  return this._rawCache.get(sql, sql);
79
129
  },
80
130
  invalidate: () => {
81
- this._rawCache.invalidate();
131
+ this._rawCache?.invalidate();
82
132
  this.cachedTables.forEach((table) => table.cache.invalidate());
83
133
  },
84
134
  };
85
135
  clientBasedOperation(operation) {
136
+ if (this.config === false)
137
+ return undefined;
86
138
  const client = (this.config.database?.client ?? "sqlite3");
87
139
  return operation[client]?.();
88
140
  }
@@ -91,7 +143,8 @@ export class ORM {
91
143
  * The backup will be saved in the location specified in the config.
92
144
  */
93
145
  async createBackup(dirname) {
94
- for (let table of this.cachedTables) {
146
+ this.requireClient();
147
+ for (const table of this.cachedTables) {
95
148
  await backupTable(table, dirname);
96
149
  }
97
150
  console.log("Database backup created.");
@@ -101,8 +154,9 @@ export class ORM {
101
154
  * @warning This will delete all the data in the tables.
102
155
  */
103
156
  async restoreBackup(dirname) {
157
+ this.requireClient();
104
158
  await disableForeignKeys(this, async (trx) => {
105
- for (let table of this.cachedTables) {
159
+ for (const table of this.cachedTables) {
106
160
  await restoreBackup(table, trx, dirname);
107
161
  }
108
162
  });
@@ -1,11 +1,16 @@
1
- import { Knex } from "knex";
2
- import { ORM } from "./orm.js";
3
1
  import { CachedQuery } from "@ghom/query";
2
+ import type { Knex } from "knex";
3
+ import { type ColumnDef, type InferColumns } from "./column.js";
4
+ import type { ORM } from "./orm.js";
4
5
  export interface MigrationData {
5
6
  table: string;
6
7
  version: number;
7
8
  }
8
- export interface TableOptions<Type extends object = object> {
9
+ /**
10
+ * Table options with typed columns.
11
+ * Type is automatically inferred from the column definitions.
12
+ */
13
+ export interface TableOptions<Columns extends Record<string, ColumnDef<any, any>>> {
9
14
  name: string;
10
15
  description?: string;
11
16
  priority?: number;
@@ -15,22 +20,48 @@ export interface TableOptions<Type extends object = object> {
15
20
  */
16
21
  caching?: number;
17
22
  migrations?: {
18
- [version: number]: (table: Knex.CreateTableBuilder) => void;
23
+ [version: number]: (builder: Knex.CreateTableBuilder) => void;
19
24
  };
20
- then?: (this: Table<Type>, table: Table<Type>) => unknown;
21
- setup: (table: Knex.CreateTableBuilder) => void;
25
+ then?: (this: Table<Columns>, table: Table<Columns>) => unknown;
26
+ /**
27
+ * Typed columns definition with automatic type inference.
28
+ *
29
+ * @example
30
+ * columns: (col) => ({
31
+ * id: col.increments(),
32
+ * username: col.string().unique(),
33
+ * age: col.integer().nullable(),
34
+ * role: col.enum(["admin", "user"]),
35
+ * })
36
+ */
37
+ columns: (col: typeof import("./column.js").col) => Columns;
22
38
  }
23
- export declare class Table<Type extends object = object> {
24
- readonly options: TableOptions<Type>;
39
+ /**
40
+ * Represents a database table with typed columns.
41
+ *
42
+ * @example
43
+ * const userTable = new Table({
44
+ * name: "user",
45
+ * columns: (col) => ({
46
+ * id: col.increments(),
47
+ * username: col.string().unique(),
48
+ * age: col.integer().nullable(),
49
+ * }),
50
+ * })
51
+ * // Type is automatically inferred as { id: number; username: string; age: number | null }
52
+ */
53
+ export declare class Table<Columns extends Record<string, ColumnDef<any, any>> = Record<string, ColumnDef<any, any>>> {
54
+ readonly options: TableOptions<Columns>;
25
55
  orm?: ORM;
26
- _whereCache?: CachedQuery<[
27
- cb: (query: Table<Type>["query"]) => unknown
28
- ], unknown>;
56
+ _whereCache?: CachedQuery<[cb: (query: Table<Columns>["query"]) => unknown], unknown>;
29
57
  _countCache?: CachedQuery<[where: string | null], number>;
30
- constructor(options: TableOptions<Type>);
31
- get db(): Knex<any, unknown[]>;
32
- get query(): Knex.QueryBuilder<Type, {
33
- _base: Type;
58
+ constructor(options: TableOptions<Columns>);
59
+ /** The inferred TypeScript type for rows of this table */
60
+ readonly $type: InferColumns<Columns>;
61
+ private requireOrm;
62
+ get client(): Knex;
63
+ get query(): Knex.QueryBuilder<InferColumns<Columns>, {
64
+ _base: InferColumns<Columns>;
34
65
  _hasSelection: false;
35
66
  _keys: never;
36
67
  _aliases: {};
@@ -39,16 +70,16 @@ export declare class Table<Type extends object = object> {
39
70
  _unionProps: never;
40
71
  }[]>;
41
72
  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>(cb: (table: Pick<Table<Type>["query"], "update" | "delete" | "insert" | "upsert" | "truncate" | "jsonInsert">) => Return) => Return;
73
+ get: <Return>(id: string, cb: (table: Pick<Table<Columns>["query"], "select" | "count" | "avg" | "sum" | "countDistinct" | "avgDistinct" | "sumDistinct">) => Return) => Return;
74
+ set: <Return>(cb: (table: Pick<Table<Columns>["query"], "update" | "delete" | "insert" | "upsert" | "truncate" | "jsonInsert">) => Return) => Return;
44
75
  count: (where?: string) => Promise<number>;
45
76
  invalidate: () => void;
46
77
  };
47
78
  count(where?: string): Promise<number>;
48
- hasColumn(name: keyof Type & string): Promise<boolean>;
49
- getColumn(name: keyof Type & string): Promise<Knex.ColumnInfo>;
50
- getColumns(): Promise<Record<keyof Type & string, Knex.ColumnInfo>>;
51
- getColumnNames(): Promise<Array<keyof Type & string>>;
79
+ hasColumn(name: keyof InferColumns<Columns> & string): Promise<boolean>;
80
+ getColumn(name: keyof InferColumns<Columns> & string): Promise<Knex.ColumnInfo>;
81
+ getColumns(): Promise<Record<keyof InferColumns<Columns> & string, Knex.ColumnInfo>>;
82
+ getColumnNames(): Promise<Array<keyof InferColumns<Columns> & string>>;
52
83
  isEmpty(): Promise<boolean>;
53
84
  make(orm: ORM): Promise<this>;
54
85
  private migrate;
package/dist/app/table.js CHANGED
@@ -1,5 +1,20 @@
1
- import { styled } from "./util.js";
2
1
  import { CachedQuery } from "@ghom/query";
2
+ import { buildColumnsSchema, col } from "./column.js";
3
+ import { styled } from "./util.js";
4
+ /**
5
+ * Represents a database table with typed columns.
6
+ *
7
+ * @example
8
+ * const userTable = new Table({
9
+ * name: "user",
10
+ * columns: (col) => ({
11
+ * id: col.increments(),
12
+ * username: col.string().unique(),
13
+ * age: col.integer().nullable(),
14
+ * }),
15
+ * })
16
+ * // Type is automatically inferred as { id: number; username: string; age: number | null }
17
+ */
3
18
  export class Table {
4
19
  options;
5
20
  orm;
@@ -8,19 +23,23 @@ export class Table {
8
23
  constructor(options) {
9
24
  this.options = options;
10
25
  }
11
- get db() {
26
+ requireOrm() {
12
27
  if (!this.orm)
13
28
  throw new Error("missing ORM");
29
+ if (!this.orm._client)
30
+ throw new Error("ORM client is not initialized");
31
+ }
32
+ get client() {
33
+ this.requireOrm();
14
34
  return this.orm.client;
15
35
  }
16
36
  get query() {
17
- return this.db(this.options.name);
37
+ return this.client(this.options.name);
18
38
  }
19
39
  get cache() {
20
40
  if (!this._whereCache || !this._countCache)
21
41
  throw new Error("missing cache");
22
- if (!this.orm)
23
- throw new Error("missing ORM");
42
+ this.requireOrm();
24
43
  return {
25
44
  get: (id, cb) => {
26
45
  return this._whereCache.get(id, cb);
@@ -42,18 +61,18 @@ export class Table {
42
61
  }
43
62
  async count(where) {
44
63
  return this.query
45
- .select(this.db.raw("count(*) as total"))
64
+ .select(this.client.raw("count(*) as total"))
46
65
  .whereRaw(where ?? "1=1")
47
66
  .then((rows) => +(rows?.[0] ?? { total: 0 }).total);
48
67
  }
49
68
  async hasColumn(name) {
50
- return this.db.schema.hasColumn(this.options.name, name);
69
+ return this.client.schema.hasColumn(this.options.name, name);
51
70
  }
52
71
  async getColumn(name) {
53
- return this.db(this.options.name).columnInfo(name);
72
+ return this.client(this.options.name).columnInfo(name);
54
73
  }
55
74
  async getColumns() {
56
- return this.db(this.options.name).columnInfo();
75
+ return this.client(this.options.name).columnInfo();
57
76
  }
58
77
  async getColumnNames() {
59
78
  return this.getColumns().then(Object.keys);
@@ -63,18 +82,22 @@ export class Table {
63
82
  }
64
83
  async make(orm) {
65
84
  this.orm = orm;
66
- this._whereCache = new CachedQuery((cb) => cb(this.query), this.options.caching ?? this.orm?.config.caching ?? Infinity);
67
- this._countCache = new CachedQuery((where) => this.count(where ?? undefined), this.options.caching ?? this.orm?.config.caching ?? Infinity);
85
+ this.requireOrm();
86
+ this._whereCache = new CachedQuery((cb) => cb(this.query), this.options.caching ?? this.orm.config.caching ?? Infinity);
87
+ this._countCache = new CachedQuery((where) => this.count(where ?? undefined), this.options.caching ?? this.orm.config.caching ?? Infinity);
68
88
  const tableNameLog = `table ${styled(this.orm, this.options.name, "highlight")}${this.options.description
69
89
  ? ` ${styled(this.orm, this.options.description, "description")}`
70
90
  : ""}`;
71
91
  try {
72
- await this.db.schema.createTable(this.options.name, this.options.setup);
92
+ await this.client.schema.createTable(this.options.name, (builder) => {
93
+ const columns = this.options.columns(col);
94
+ buildColumnsSchema(builder, columns);
95
+ });
73
96
  this.orm.config.logger?.log(`created table ${tableNameLog}`);
74
97
  }
75
98
  catch (error) {
76
99
  if (error.toString().includes("syntax error")) {
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!`);
100
+ this.orm.config.logger?.error(`you need to implement the "columns" callback in options of your ${styled(this.orm, this.options.name, "highlight")} table!`);
78
101
  throw error;
79
102
  }
80
103
  else {
@@ -91,8 +114,10 @@ export class Table {
91
114
  this.orm.config.logger?.error(error);
92
115
  throw error;
93
116
  }
94
- if ((await this.count()) === 0)
95
- await this.options.then?.bind(this)(this);
117
+ if ((await this.count()) === 0) {
118
+ const thenFn = this.options.then;
119
+ await thenFn?.bind(this)(this);
120
+ }
96
121
  return this;
97
122
  }
98
123
  async migrate() {
@@ -101,7 +126,7 @@ export class Table {
101
126
  const migrations = new Map(Object.entries(this.options.migrations)
102
127
  .sort((a, b) => Number(a[0]) - Number(b[0]))
103
128
  .map((entry) => [Number(entry[0]), entry[1]]));
104
- const fromDatabase = await this.db("migration")
129
+ const fromDatabase = await this.client("migration")
105
130
  .where("table", this.options.name)
106
131
  .first();
107
132
  const data = fromDatabase || {
@@ -110,17 +135,14 @@ export class Table {
110
135
  };
111
136
  const baseVersion = data.version;
112
137
  for (const [version, migration] of migrations) {
113
- await this.db.schema.alterTable(this.options.name, (builder) => {
138
+ await this.client.schema.alterTable(this.options.name, (builder) => {
114
139
  if (version <= data.version)
115
140
  return;
116
141
  migration(builder);
117
142
  data.version = version;
118
143
  });
119
144
  }
120
- await this.db("migration")
121
- .insert(data)
122
- .onConflict("table")
123
- .merge();
145
+ await this.client("migration").insert(data).onConflict("table").merge();
124
146
  return baseVersion === data.version ? false : data.version;
125
147
  }
126
148
  }
@@ -4,7 +4,7 @@ export type TextStyle = Parameters<typeof util.styleText>[0];
4
4
  export declare const DEFAULT_BACKUP_LOCATION: string;
5
5
  export declare const DEFAULT_BACKUP_CHUNK_SIZE: number;
6
6
  export declare const DEFAULT_LOGGER_HIGHLIGHT = "blueBright";
7
- export declare const DEFAULT_LOGGER_DESCRIPTION = "grey";
7
+ export declare const DEFAULT_LOGGER_DESCRIPTION = "gray";
8
8
  export declare const DEFAULT_LOGGER_RAW_VALUE = "magentaBright";
9
9
  declare let isCJS: boolean;
10
10
  export { isCJS };
package/dist/app/util.js CHANGED
@@ -1,15 +1,15 @@
1
- import util from "node:util";
2
- import path from "node:path";
3
1
  import fs from "node:fs";
2
+ import path from "node:path";
3
+ import util from "node:util";
4
4
  export const DEFAULT_BACKUP_LOCATION = path.join(process.cwd(), "backup");
5
5
  export const DEFAULT_BACKUP_CHUNK_SIZE = 5 * 1024 * 1024; // 5MB
6
6
  export const DEFAULT_LOGGER_HIGHLIGHT = "blueBright";
7
- export const DEFAULT_LOGGER_DESCRIPTION = "grey";
7
+ export const DEFAULT_LOGGER_DESCRIPTION = "gray";
8
8
  export const DEFAULT_LOGGER_RAW_VALUE = "magentaBright";
9
9
  let isCJS = false;
10
10
  try {
11
11
  const pack = JSON.parse(fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8"));
12
- isCJS = pack.type === "commonjs" || pack.type == void 0;
12
+ isCJS = pack.type === "commonjs" || pack.type === void 0;
13
13
  }
14
14
  catch {
15
15
  throw new Error("Missing package.json: Can't detect the type of modules.\n" +
@@ -18,7 +18,8 @@ catch {
18
18
  }
19
19
  export { isCJS };
20
20
  export function styled(orm, message, style) {
21
- return util.styleText(orm.config.loggerStyles?.[style] ??
21
+ const config = orm.config !== false ? orm.config : undefined;
22
+ return util.styleText(config?.loggerStyles?.[style] ??
22
23
  (style === "highlight"
23
24
  ? DEFAULT_LOGGER_HIGHLIGHT
24
25
  : style === "rawValue"
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
+ export * from "./app/backup.js";
2
+ export * from "./app/column.js";
1
3
  export * from "./app/orm.js";
2
4
  export * from "./app/table.js";
3
- export * from "./app/backup.js";
4
5
  export * from "./app/util.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
+ export * from "./app/backup.js";
2
+ export * from "./app/column.js";
1
3
  export * from "./app/orm.js";
2
4
  export * from "./app/table.js";
3
- export * from "./app/backup.js";
4
5
  export * from "./app/util.js";
package/package.json CHANGED
@@ -1,47 +1,43 @@
1
- {
2
- "name": "@ghom/orm",
3
- "version": "1.9.2",
4
- "license": "MIT",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "description": "TypeScript KnexJS ORM & handler",
9
- "homepage": "https://github.com/GhomKrosmonaute/orm",
10
- "prettier": {
11
- "semi": false
12
- },
13
- "scripts": {
14
- "format": "prettier --write src tsconfig.json tests",
15
- "build": "rimraf dist && tsc",
16
- "test": "npm run build && node --experimental-vm-modules node_modules/jest/bin/jest.js tests/test.js --detectOpenHandles",
17
- "prepublishOnly": "npm run format && npm test"
18
- },
19
- "devDependencies": {
20
- "@types/jest": "^29.5.6",
21
- "@types/node": "^22.0.0",
22
- "dotenv": "^16.3.1",
23
- "jest": "^29.7.0",
24
- "prettier": "^3.0.3",
25
- "rimraf": "^6.0.1",
26
- "typescript": "^5.2.2"
27
- },
28
- "optionalDependencies": {
29
- "mysql2": "^3.6.2",
30
- "pg": "^8.11.3",
31
- "sqlite3": "^5.1.6"
32
- },
33
- "dependencies": {
34
- "@ghom/handler": "^3.1.0",
35
- "@ghom/query": "1.0.0",
36
- "csv-parser": "^3.0.0",
37
- "json-2-csv": "^5.5.6",
38
- "knex": "^3.0.1"
39
- },
40
- "engines": {
41
- "node": ">=22.0.0"
42
- },
43
- "repository": {
44
- "url": "https://github.com/GhomKrosmonaute/orm.git",
45
- "type": "git"
46
- }
47
- }
1
+ {
2
+ "name": "@ghom/orm",
3
+ "version": "2.0.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "description": "TypeScript KnexJS ORM & handler",
9
+ "homepage": "https://github.com/GhomKrosmonaute/orm",
10
+ "scripts": {
11
+ "format": "biome format --write src",
12
+ "lint": "biome lint .",
13
+ "check": "biome check --write .",
14
+ "build": "rimraf dist && tsc",
15
+ "test": "bun test",
16
+ "prepublishOnly": "npm run check && npm run build && npm test"
17
+ },
18
+ "devDependencies": {
19
+ "@biomejs/biome": "^2.3.13",
20
+ "@types/bun": "^1.1.0",
21
+ "rimraf": "^6.0.1",
22
+ "typescript": "^5.2.2"
23
+ },
24
+ "optionalDependencies": {
25
+ "mysql2": "^3.6.2",
26
+ "pg": "^8.11.3",
27
+ "sqlite3": "^5.1.6"
28
+ },
29
+ "dependencies": {
30
+ "@ghom/handler": "^3.1.0",
31
+ "@ghom/query": "1.0.0",
32
+ "csv-parser": "^3.0.0",
33
+ "json-2-csv": "^5.5.6",
34
+ "knex": "^3.0.1"
35
+ },
36
+ "engines": {
37
+ "node": ">=22.0.0"
38
+ },
39
+ "repository": {
40
+ "url": "https://github.com/GhomKrosmonaute/orm.git",
41
+ "type": "git"
42
+ }
43
+ }
package/readme.md CHANGED
@@ -41,6 +41,25 @@ const orm = new ORM({
41
41
  await orm.init()
42
42
  ```
43
43
 
44
+ ### Unconnected ORM
45
+
46
+ You can also create an ORM instance without connecting to a database. This is useful when you only need to export types or prepare the ORM structure for a future database connection.
47
+
48
+ ```typescript
49
+ import { ORM } from "@ghom/orm"
50
+
51
+ const orm = new ORM(false)
52
+
53
+ orm.isConnected // false
54
+ orm.cachedTables // []
55
+ orm.cachedTableNames // []
56
+
57
+ // Methods requiring a database connection will throw an error
58
+ orm.init() // throws Error
59
+ orm.hasTable("user") // throws Error
60
+ orm.raw("SELECT 1") // throws Error
61
+ ```
62
+
44
63
  ## Add tables
45
64
 
46
65
  The tables are automatically loaded from the `location` directory.