@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.
- package/.github/workflows/test.yml +40 -0
- package/.run/All Tests.run.xml +22 -0
- package/dist/app/backup.d.ts +6 -0
- package/dist/app/backup.js +119 -0
- package/dist/app/caching.d.ts +18 -0
- package/dist/app/caching.js +36 -0
- package/dist/{typings/app → app}/orm.d.ts +36 -7
- package/dist/app/orm.js +109 -0
- package/dist/{typings/app → app}/table.d.ts +16 -0
- package/dist/{esm/app → app}/table.js +40 -8
- package/dist/app/util.d.ts +9 -0
- package/dist/app/util.js +18 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/package.json +17 -6
- package/readme.md +95 -8
- package/tests/tables/a.js +24 -21
- package/tests/tables/b.js +27 -24
- package/tests/tables/c.js +15 -12
- package/tests/test.js +120 -43
- package/tsconfig.json +8 -4
- package/dist/cjs/app/orm.js +0 -94
- package/dist/cjs/app/table.js +0 -104
- package/dist/cjs/index.js +0 -18
- package/dist/esm/app/orm.js +0 -67
- package/dist/esm/index.js +0 -2
- package/dist/typings/index.d.ts +0 -2
- package/fixup.sh +0 -11
- package/src/app/orm.ts +0 -195
- package/src/app/table.ts +0 -164
- package/src/index.ts +0 -2
- package/tsconfig-cjs.json +0 -10
- package/tsconfig-esm.json +0 -8
package/dist/cjs/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./app/orm.js"), exports);
|
|
18
|
-
__exportStar(require("./app/table.js"), exports);
|
package/dist/esm/app/orm.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import url from "url";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { Handler } from "@ghom/handler";
|
|
5
|
-
import { default as knex } from "knex";
|
|
6
|
-
import { Table } from "./table.js";
|
|
7
|
-
const defaultBackupDir = path.join(process.cwd(), "backup");
|
|
8
|
-
const pack = JSON.parse(fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8"));
|
|
9
|
-
const isCJS = pack.type === "commonjs" || pack.type == void 0;
|
|
10
|
-
export class ORM {
|
|
11
|
-
config;
|
|
12
|
-
database;
|
|
13
|
-
handler;
|
|
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.location, {
|
|
24
|
-
loader: (filepath) => import(isCJS ? filepath : url.pathToFileURL(filepath).href).then((file) => file.default),
|
|
25
|
-
pattern: /\.js$/,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
get cachedTables() {
|
|
29
|
-
return [...this.handler.elements.values()];
|
|
30
|
-
}
|
|
31
|
-
get cachedTableNames() {
|
|
32
|
-
return this.cachedTables.map((table) => table.options.name);
|
|
33
|
-
}
|
|
34
|
-
hasCachedTable(name) {
|
|
35
|
-
return this.cachedTables.some((table) => table.options.name);
|
|
36
|
-
}
|
|
37
|
-
async hasTable(name) {
|
|
38
|
-
return this.database.schema.hasTable(name);
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Handle the table files and create the tables in the database.
|
|
42
|
-
*/
|
|
43
|
-
async init() {
|
|
44
|
-
await this.handler.init();
|
|
45
|
-
try {
|
|
46
|
-
await this.database.raw("PRAGMA foreign_keys = ON;");
|
|
47
|
-
}
|
|
48
|
-
catch (error) { }
|
|
49
|
-
const migration = new Table({
|
|
50
|
-
name: "migration",
|
|
51
|
-
priority: Infinity,
|
|
52
|
-
setup: (table) => {
|
|
53
|
-
table.string("table").unique().notNullable();
|
|
54
|
-
table.integer("version").notNullable();
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
migration.orm = this;
|
|
58
|
-
await migration.make();
|
|
59
|
-
for (const table of this.cachedTables.sort((a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0))) {
|
|
60
|
-
table.orm = this;
|
|
61
|
-
await table.make();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
raw(sql) {
|
|
65
|
-
return this.database.raw(sql);
|
|
66
|
-
}
|
|
67
|
-
}
|
package/dist/esm/index.js
DELETED
package/dist/typings/index.d.ts
DELETED
package/fixup.sh
DELETED
package/src/app/orm.ts
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import fs from "fs"
|
|
2
|
-
import url from "url"
|
|
3
|
-
import path from "path"
|
|
4
|
-
import { Handler } from "@ghom/handler"
|
|
5
|
-
import { Knex, default as knex } from "knex"
|
|
6
|
-
import { MigrationData, Table } from "./table.js"
|
|
7
|
-
import chalk, { Color } from "chalk"
|
|
8
|
-
|
|
9
|
-
const defaultBackupDir = path.join(process.cwd(), "backup")
|
|
10
|
-
|
|
11
|
-
const pack = JSON.parse(
|
|
12
|
-
fs.readFileSync(path.join(process.cwd(), "package.json"), "utf8"),
|
|
13
|
-
)
|
|
14
|
-
const isCJS = pack.type === "commonjs" || pack.type == void 0
|
|
15
|
-
|
|
16
|
-
export interface ILogger {
|
|
17
|
-
log: (message: string) => void
|
|
18
|
-
error: (error: string | Error) => void
|
|
19
|
-
warn: (warning: string) => void
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ORMConfig {
|
|
23
|
-
/**
|
|
24
|
-
* path to the directory that contains js files of tables
|
|
25
|
-
*/
|
|
26
|
-
location: string
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* database configuration
|
|
30
|
-
*/
|
|
31
|
-
database?: Knex.Config
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Logger used to log the table files loaded or created.
|
|
35
|
-
*/
|
|
36
|
-
logger?: ILogger
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Pattern used on logs when the table files are loaded or created. <br>
|
|
40
|
-
* Based on Chalk color-method names.
|
|
41
|
-
*/
|
|
42
|
-
loggerColors?: {
|
|
43
|
-
highlight: typeof Color
|
|
44
|
-
rawValue: typeof Color
|
|
45
|
-
description: typeof Color
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export class ORM {
|
|
50
|
-
public database: Knex
|
|
51
|
-
public handler: Handler<Table<any>>
|
|
52
|
-
|
|
53
|
-
constructor(public config: ORMConfig) {
|
|
54
|
-
this.database = knex(
|
|
55
|
-
config.database ?? {
|
|
56
|
-
client: "sqlite3",
|
|
57
|
-
useNullAsDefault: true,
|
|
58
|
-
connection: {
|
|
59
|
-
filename: ":memory:",
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
this.handler = new Handler(config.location, {
|
|
65
|
-
loader: (filepath) =>
|
|
66
|
-
import(isCJS ? filepath : url.pathToFileURL(filepath).href).then(
|
|
67
|
-
(file) => file.default,
|
|
68
|
-
),
|
|
69
|
-
pattern: /\.js$/,
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
get cachedTables() {
|
|
74
|
-
return [...this.handler.elements.values()]
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
get cachedTableNames() {
|
|
78
|
-
return this.cachedTables.map((table) => table.options.name)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
hasCachedTable(name: string) {
|
|
82
|
-
return this.cachedTables.some((table) => table.options.name)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async hasTable(name: string): Promise<boolean> {
|
|
86
|
-
return this.database.schema.hasTable(name)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Handle the table files and create the tables in the database.
|
|
91
|
-
*/
|
|
92
|
-
async init() {
|
|
93
|
-
await this.handler.init()
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
await this.database.raw("PRAGMA foreign_keys = ON;")
|
|
97
|
-
} catch (error) {}
|
|
98
|
-
|
|
99
|
-
const migration = new Table<MigrationData>({
|
|
100
|
-
name: "migration",
|
|
101
|
-
priority: Infinity,
|
|
102
|
-
setup: (table) => {
|
|
103
|
-
table.string("table").unique().notNullable()
|
|
104
|
-
table.integer("version").notNullable()
|
|
105
|
-
},
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
migration.orm = this
|
|
109
|
-
await migration.make()
|
|
110
|
-
|
|
111
|
-
for (const table of this.cachedTables.sort(
|
|
112
|
-
(a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0),
|
|
113
|
-
)) {
|
|
114
|
-
table.orm = this
|
|
115
|
-
await table.make()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
raw(sql: Knex.Value): Knex.Raw {
|
|
120
|
-
return this.database.raw(sql)
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// /**
|
|
124
|
-
// * Extract the database to a CSV file for each table.
|
|
125
|
-
// */
|
|
126
|
-
// async createBackup(dir = defaultBackupDir) {
|
|
127
|
-
// const tables = [...this.handler.elements.values()]
|
|
128
|
-
//
|
|
129
|
-
// for (const table of tables) {
|
|
130
|
-
// await this.database
|
|
131
|
-
// .select()
|
|
132
|
-
// .from(table.options.name)
|
|
133
|
-
// .then(async (rows) => {
|
|
134
|
-
// const csv = rows.map((row) => Object.values(row).join(",")).join("\n")
|
|
135
|
-
//
|
|
136
|
-
// return fs.promises.writeFile(
|
|
137
|
-
// path.join(dir, `${table.options.name}.csv`),
|
|
138
|
-
// csv,
|
|
139
|
-
// "utf8",
|
|
140
|
-
// )
|
|
141
|
-
// })
|
|
142
|
-
// }
|
|
143
|
-
// }
|
|
144
|
-
//
|
|
145
|
-
// /**
|
|
146
|
-
// * Import a CSV file for each table to the database.
|
|
147
|
-
// */
|
|
148
|
-
// async restoreBackup(dir = defaultBackupDir) {
|
|
149
|
-
// const tables = [...this.handler.elements.values()].sort(
|
|
150
|
-
// (a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0),
|
|
151
|
-
// )
|
|
152
|
-
//
|
|
153
|
-
// for (const table of tables) {
|
|
154
|
-
// const columnInfo = await table.getColumns()
|
|
155
|
-
//
|
|
156
|
-
// let csv: string
|
|
157
|
-
//
|
|
158
|
-
// try {
|
|
159
|
-
// csv = await fs.promises.readFile(
|
|
160
|
-
// path.join(dir, `${table.options.name}.csv`),
|
|
161
|
-
// "utf8",
|
|
162
|
-
// )
|
|
163
|
-
// } catch (error) {
|
|
164
|
-
// this.config.logger?.warn(
|
|
165
|
-
// `missing backup file for table ${chalk[
|
|
166
|
-
// this.config.loggerColors?.highlight ?? "blueBright"
|
|
167
|
-
// ](table.options.name)}`,
|
|
168
|
-
// )
|
|
169
|
-
//
|
|
170
|
-
// continue
|
|
171
|
-
// }
|
|
172
|
-
//
|
|
173
|
-
// if (csv.trim().length === 0) continue
|
|
174
|
-
//
|
|
175
|
-
// const rows = csv
|
|
176
|
-
// .split("\n")
|
|
177
|
-
// .map((row) => row.split(","))
|
|
178
|
-
// .map((row) => {
|
|
179
|
-
// const data: any = {}
|
|
180
|
-
//
|
|
181
|
-
// let index = 0
|
|
182
|
-
//
|
|
183
|
-
// for (const [name, info] of Object.entries(columnInfo)) {
|
|
184
|
-
// data[name] =
|
|
185
|
-
// info.type === "integer" ? Number(row[index]) : row[index]
|
|
186
|
-
// index++
|
|
187
|
-
// }
|
|
188
|
-
//
|
|
189
|
-
// return data
|
|
190
|
-
// })
|
|
191
|
-
//
|
|
192
|
-
// await this.database(table.options.name).insert(rows)
|
|
193
|
-
// }
|
|
194
|
-
// }
|
|
195
|
-
}
|
package/src/app/table.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk"
|
|
2
|
-
import { Knex } from "knex"
|
|
3
|
-
import { ORM } from "./orm.js"
|
|
4
|
-
|
|
5
|
-
export interface MigrationData {
|
|
6
|
-
table: string
|
|
7
|
-
version: number
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface TableOptions<Type extends object = object> {
|
|
11
|
-
name: string
|
|
12
|
-
description?: string
|
|
13
|
-
priority?: number
|
|
14
|
-
migrations?: { [version: number]: (table: Knex.CreateTableBuilder) => void }
|
|
15
|
-
then?: (this: Table<Type>, table: Table<Type>) => unknown
|
|
16
|
-
setup: (table: Knex.CreateTableBuilder) => void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export class Table<Type extends object = object> {
|
|
20
|
-
orm?: ORM
|
|
21
|
-
|
|
22
|
-
constructor(public readonly options: TableOptions<Type>) {}
|
|
23
|
-
|
|
24
|
-
get db() {
|
|
25
|
-
if (!this.orm) throw new Error("missing ORM")
|
|
26
|
-
return this.orm.database
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
get query() {
|
|
30
|
-
return this.db<Type>(this.options.name)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async count(where?: string): Promise<number> {
|
|
34
|
-
return this.query
|
|
35
|
-
.select(this.db.raw("count(*) as total"))
|
|
36
|
-
.whereRaw(where ?? "1=1")
|
|
37
|
-
.then((rows) => (rows[0] as unknown as { total: number }).total)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async hasColumn(name: keyof Type & string): Promise<boolean> {
|
|
41
|
-
return this.db.schema.hasColumn(this.options.name, name as string)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async getColumn(name: keyof Type & string): Promise<Knex.ColumnInfo> {
|
|
45
|
-
return this.db(this.options.name).columnInfo(name)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async getColumns(): Promise<Record<keyof Type & string, Knex.ColumnInfo>> {
|
|
49
|
-
return this.db(this.options.name).columnInfo()
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async getColumnNames(): Promise<Array<keyof Type & string>> {
|
|
53
|
-
return this.getColumns().then(Object.keys) as Promise<
|
|
54
|
-
Array<keyof Type & string>
|
|
55
|
-
>
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async isEmpty(): Promise<boolean> {
|
|
59
|
-
return this.count().then((count) => count === 0)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async make(): Promise<this> {
|
|
63
|
-
if (!this.orm) throw new Error("missing ORM")
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
await this.db.schema.createTable(this.options.name, this.options.setup)
|
|
67
|
-
|
|
68
|
-
this.orm.config.logger?.log(
|
|
69
|
-
`created table ${chalk[
|
|
70
|
-
this.orm.config.loggerColors?.highlight ?? "blueBright"
|
|
71
|
-
](this.options.name)}${
|
|
72
|
-
this.options.description
|
|
73
|
-
? ` ${chalk[this.orm.config.loggerColors?.description ?? "grey"](
|
|
74
|
-
this.options.description,
|
|
75
|
-
)}`
|
|
76
|
-
: ""
|
|
77
|
-
}`,
|
|
78
|
-
)
|
|
79
|
-
} catch (error: any) {
|
|
80
|
-
if (error.toString().includes("syntax error")) {
|
|
81
|
-
this.orm.config.logger?.error(
|
|
82
|
-
`you need to implement the "setup" method in options of your ${chalk[
|
|
83
|
-
this.orm.config.loggerColors?.highlight ?? "blueBright"
|
|
84
|
-
](this.options.name)} table!`,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
throw error
|
|
88
|
-
} else {
|
|
89
|
-
this.orm.config.logger?.log(
|
|
90
|
-
`loaded table ${chalk[
|
|
91
|
-
this.orm.config.loggerColors?.highlight ?? "blueBright"
|
|
92
|
-
](this.options.name)}${
|
|
93
|
-
this.options.description
|
|
94
|
-
? ` ${chalk[this.orm.config.loggerColors?.description ?? "grey"](
|
|
95
|
-
this.options.description,
|
|
96
|
-
)}`
|
|
97
|
-
: ""
|
|
98
|
-
}`,
|
|
99
|
-
)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const migrated = await this.migrate()
|
|
105
|
-
|
|
106
|
-
if (migrated !== false) {
|
|
107
|
-
this.orm.config.logger?.log(
|
|
108
|
-
`migrated table ${chalk[
|
|
109
|
-
this.orm.config.loggerColors?.highlight ?? "blueBright"
|
|
110
|
-
](this.options.name)} to version ${chalk[
|
|
111
|
-
this.orm.config.loggerColors?.rawValue ?? "magentaBright"
|
|
112
|
-
](migrated)}`,
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
} catch (error: any) {
|
|
116
|
-
this.orm.config.logger?.error(error)
|
|
117
|
-
|
|
118
|
-
throw error
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if ((await this.count()) === 0) await this.options.then?.bind(this)(this)
|
|
122
|
-
|
|
123
|
-
return this
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private async migrate(): Promise<false | number> {
|
|
127
|
-
if (!this.options.migrations) return false
|
|
128
|
-
|
|
129
|
-
const migrations = new Map<
|
|
130
|
-
number,
|
|
131
|
-
(table: Knex.CreateTableBuilder) => void
|
|
132
|
-
>(
|
|
133
|
-
Object.entries(this.options.migrations)
|
|
134
|
-
.sort((a, b) => Number(a[0]) - Number(b[0]))
|
|
135
|
-
.map((entry) => [Number(entry[0]), entry[1]]),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
const fromDatabase = await this.db<MigrationData>("migration")
|
|
139
|
-
.where("table", this.options.name)
|
|
140
|
-
.first()
|
|
141
|
-
|
|
142
|
-
const data = fromDatabase || {
|
|
143
|
-
table: this.options.name,
|
|
144
|
-
version: -Infinity,
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const baseVersion = data.version
|
|
148
|
-
|
|
149
|
-
await this.db.schema.alterTable(this.options.name, (builder) => {
|
|
150
|
-
migrations.forEach((migration, version) => {
|
|
151
|
-
if (version <= data.version) return
|
|
152
|
-
migration(builder)
|
|
153
|
-
data.version = version
|
|
154
|
-
})
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
await this.db<MigrationData>("migration")
|
|
158
|
-
.insert(data)
|
|
159
|
-
.onConflict("table")
|
|
160
|
-
.merge()
|
|
161
|
-
|
|
162
|
-
return baseVersion === data.version ? false : data.version
|
|
163
|
-
}
|
|
164
|
-
}
|
package/src/index.ts
DELETED
package/tsconfig-cjs.json
DELETED