@bunnykit/orm 0.1.5 → 0.1.6
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/README.md +381 -82
- package/dist/bin/bunny.js +133 -19
- package/dist/src/config/BunnyConfig.d.ts +28 -0
- package/dist/src/config/BunnyConfig.js +14 -0
- package/dist/src/connection/Connection.d.ts +20 -1
- package/dist/src/connection/Connection.js +80 -2
- package/dist/src/connection/ConnectionManager.d.ts +40 -0
- package/dist/src/connection/ConnectionManager.js +104 -0
- package/dist/src/connection/TenantContext.d.ts +15 -0
- package/dist/src/connection/TenantContext.js +22 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +3 -0
- package/dist/src/model/BelongsToMany.js +9 -6
- package/dist/src/model/Model.d.ts +5 -0
- package/dist/src/model/Model.js +57 -20
- package/dist/src/model/MorphRelations.js +10 -10
- package/dist/src/query/Builder.d.ts +44 -5
- package/dist/src/query/Builder.js +252 -113
- package/dist/src/query/grammars/Grammar.d.ts +19 -0
- package/dist/src/query/grammars/Grammar.js +47 -0
- package/dist/src/query/grammars/MySqlGrammar.d.ts +13 -0
- package/dist/src/query/grammars/MySqlGrammar.js +59 -0
- package/dist/src/query/grammars/PostgresGrammar.d.ts +13 -0
- package/dist/src/query/grammars/PostgresGrammar.js +62 -0
- package/dist/src/query/grammars/SQLiteGrammar.d.ts +14 -0
- package/dist/src/query/grammars/SQLiteGrammar.js +63 -0
- package/dist/src/schema/Schema.js +44 -26
- package/dist/src/typegen/TypeGenerator.js +4 -2
- package/dist/src/types/index.d.ts +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Grammar } from "./Grammar.js";
|
|
2
|
+
export class MySqlGrammar extends Grammar {
|
|
3
|
+
wrap(value) {
|
|
4
|
+
if (value.includes(" as ")) {
|
|
5
|
+
const [column, alias] = value.split(/\s+as\s+/i);
|
|
6
|
+
return `${this.wrap(column)} AS ${this.wrap(alias)}`;
|
|
7
|
+
}
|
|
8
|
+
if (value.includes(".")) {
|
|
9
|
+
return value.split(".").map((v) => this.wrap(v)).join(".");
|
|
10
|
+
}
|
|
11
|
+
if (value === "*")
|
|
12
|
+
return value;
|
|
13
|
+
return `\`${value}\``;
|
|
14
|
+
}
|
|
15
|
+
compileRandomOrder() {
|
|
16
|
+
return "ORDER BY RAND()";
|
|
17
|
+
}
|
|
18
|
+
compileDateWhere(type, column, operator, value) {
|
|
19
|
+
switch (type) {
|
|
20
|
+
case "date":
|
|
21
|
+
return `DATE(${column}) ${operator} ${this.escape(value)}`;
|
|
22
|
+
case "day":
|
|
23
|
+
return `DAY(${column}) ${operator} ${this.escape(value)}`;
|
|
24
|
+
case "month":
|
|
25
|
+
return `MONTH(${column}) ${operator} ${this.escape(value)}`;
|
|
26
|
+
case "year":
|
|
27
|
+
return `YEAR(${column}) ${operator} ${this.escape(value)}`;
|
|
28
|
+
case "time":
|
|
29
|
+
return `TIME(${column}) ${operator} ${this.escape(value)}`;
|
|
30
|
+
default:
|
|
31
|
+
return `${column} ${operator} ${this.escape(value)}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
compileInsertOrIgnore(table, columns, values) {
|
|
35
|
+
return `INSERT IGNORE INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")}`;
|
|
36
|
+
}
|
|
37
|
+
compileUpsert(table, columns, values, _uniqueBy, updateColumns) {
|
|
38
|
+
const updateCols = updateColumns
|
|
39
|
+
.map((c) => `${this.wrap(c)} = VALUES(${this.wrap(c)})`)
|
|
40
|
+
.join(", ");
|
|
41
|
+
return `INSERT INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")} ON DUPLICATE KEY UPDATE ${updateCols}`;
|
|
42
|
+
}
|
|
43
|
+
compileJsonContains(column, value) {
|
|
44
|
+
return `JSON_CONTAINS(${column}, ${this.escape(JSON.stringify(value))})`;
|
|
45
|
+
}
|
|
46
|
+
compileJsonLength(column, operator, value) {
|
|
47
|
+
return `JSON_LENGTH(${column}) ${operator} ${this.escape(value)}`;
|
|
48
|
+
}
|
|
49
|
+
compileRegexp(column, value, not) {
|
|
50
|
+
const op = not ? "NOT REGEXP" : "REGEXP";
|
|
51
|
+
return `${column} ${op} ${this.escape(value)}`;
|
|
52
|
+
}
|
|
53
|
+
compileFullText(columns, value) {
|
|
54
|
+
return `MATCH (${columns.join(", ")}) AGAINST (${this.escape(value)})`;
|
|
55
|
+
}
|
|
56
|
+
compileExplain(sql) {
|
|
57
|
+
return `EXPLAIN ${sql}`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Grammar } from "./Grammar.js";
|
|
2
|
+
export declare class PostgresGrammar extends Grammar {
|
|
3
|
+
wrap(value: string): string;
|
|
4
|
+
compileRandomOrder(): string;
|
|
5
|
+
compileDateWhere(type: string, column: string, operator: string, value: any): string;
|
|
6
|
+
compileInsertOrIgnore(table: string, columns: string[], values: string[]): string;
|
|
7
|
+
compileUpsert(table: string, columns: string[], values: string[], uniqueBy: string[], updateColumns: string[]): string;
|
|
8
|
+
compileJsonContains(column: string, value: any): string;
|
|
9
|
+
compileJsonLength(column: string, operator: string, value: any): string;
|
|
10
|
+
compileRegexp(column: string, value: string, not: boolean): string;
|
|
11
|
+
compileFullText(columns: string[], value: string): string;
|
|
12
|
+
compileExplain(sql: string): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Grammar } from "./Grammar.js";
|
|
2
|
+
export class PostgresGrammar extends Grammar {
|
|
3
|
+
wrap(value) {
|
|
4
|
+
if (value.includes(" as ")) {
|
|
5
|
+
const [column, alias] = value.split(/\s+as\s+/i);
|
|
6
|
+
return `${this.wrap(column)} AS ${this.wrap(alias)}`;
|
|
7
|
+
}
|
|
8
|
+
if (value.includes(".")) {
|
|
9
|
+
return value.split(".").map((v) => this.wrap(v)).join(".");
|
|
10
|
+
}
|
|
11
|
+
if (value === "*")
|
|
12
|
+
return value;
|
|
13
|
+
return `"${value}"`;
|
|
14
|
+
}
|
|
15
|
+
compileRandomOrder() {
|
|
16
|
+
return "ORDER BY RANDOM()";
|
|
17
|
+
}
|
|
18
|
+
compileDateWhere(type, column, operator, value) {
|
|
19
|
+
switch (type) {
|
|
20
|
+
case "date":
|
|
21
|
+
return `(${column})::date ${operator} ${this.escape(value)}`;
|
|
22
|
+
case "day":
|
|
23
|
+
return `EXTRACT(DAY FROM ${column}) ${operator} ${this.escape(value)}`;
|
|
24
|
+
case "month":
|
|
25
|
+
return `EXTRACT(MONTH FROM ${column}) ${operator} ${this.escape(value)}`;
|
|
26
|
+
case "year":
|
|
27
|
+
return `EXTRACT(YEAR FROM ${column}) ${operator} ${this.escape(value)}`;
|
|
28
|
+
case "time":
|
|
29
|
+
return `(${column})::time ${operator} ${this.escape(value)}`;
|
|
30
|
+
default:
|
|
31
|
+
return `${column} ${operator} ${this.escape(value)}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
compileInsertOrIgnore(table, columns, values) {
|
|
35
|
+
return `INSERT INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")} ON CONFLICT DO NOTHING`;
|
|
36
|
+
}
|
|
37
|
+
compileUpsert(table, columns, values, uniqueBy, updateColumns) {
|
|
38
|
+
const updateCols = updateColumns
|
|
39
|
+
.map((c) => `${this.wrap(c)} = EXCLUDED.${this.wrap(c)}`)
|
|
40
|
+
.join(", ");
|
|
41
|
+
return `INSERT INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")} ON CONFLICT (${uniqueBy.map((c) => this.wrap(c)).join(", ")}) DO UPDATE SET ${updateCols}`;
|
|
42
|
+
}
|
|
43
|
+
compileJsonContains(column, value) {
|
|
44
|
+
return `${column} @> ${this.escape(JSON.stringify([value]))}`;
|
|
45
|
+
}
|
|
46
|
+
compileJsonLength(column, operator, value) {
|
|
47
|
+
return `jsonb_array_length(${column}) ${operator} ${this.escape(value)}`;
|
|
48
|
+
}
|
|
49
|
+
compileRegexp(column, value, not) {
|
|
50
|
+
const op = not ? "!~" : "~";
|
|
51
|
+
return `${column} ${op} ${this.escape(value)}`;
|
|
52
|
+
}
|
|
53
|
+
compileFullText(columns, value) {
|
|
54
|
+
const cols = columns.length > 1
|
|
55
|
+
? `concat_ws(' ', ${columns.join(", ")})`
|
|
56
|
+
: columns[0];
|
|
57
|
+
return `to_tsvector('english', ${cols}) @@ plainto_tsquery('english', ${this.escape(value)})`;
|
|
58
|
+
}
|
|
59
|
+
compileExplain(sql) {
|
|
60
|
+
return `EXPLAIN (FORMAT JSON) ${sql}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Grammar } from "./Grammar.js";
|
|
2
|
+
export declare class SQLiteGrammar extends Grammar {
|
|
3
|
+
wrap(value: string): string;
|
|
4
|
+
compileRandomOrder(): string;
|
|
5
|
+
compileOffset(offset: number, limit?: number): string;
|
|
6
|
+
compileDateWhere(type: string, column: string, operator: string, value: any): string;
|
|
7
|
+
compileInsertOrIgnore(table: string, columns: string[], values: string[]): string;
|
|
8
|
+
compileUpsert(table: string, columns: string[], values: string[], uniqueBy: string[], updateColumns: string[]): string;
|
|
9
|
+
compileJsonContains(column: string, value: any): string;
|
|
10
|
+
compileJsonLength(column: string, operator: string, value: any): string;
|
|
11
|
+
compileRegexp(column: string, value: string, not: boolean): string;
|
|
12
|
+
compileFullText(columns: string[], value: string): string;
|
|
13
|
+
compileExplain(sql: string): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Grammar } from "./Grammar.js";
|
|
2
|
+
export class SQLiteGrammar extends Grammar {
|
|
3
|
+
wrap(value) {
|
|
4
|
+
if (value.includes(" as ")) {
|
|
5
|
+
const [column, alias] = value.split(/\s+as\s+/i);
|
|
6
|
+
return `${this.wrap(column)} AS ${this.wrap(alias)}`;
|
|
7
|
+
}
|
|
8
|
+
if (value.includes(".")) {
|
|
9
|
+
return value.split(".").map((v) => this.wrap(v)).join(".");
|
|
10
|
+
}
|
|
11
|
+
if (value === "*")
|
|
12
|
+
return value;
|
|
13
|
+
return `"${value}"`;
|
|
14
|
+
}
|
|
15
|
+
compileRandomOrder() {
|
|
16
|
+
return "ORDER BY RANDOM()";
|
|
17
|
+
}
|
|
18
|
+
compileOffset(offset, limit) {
|
|
19
|
+
const limitSql = limit === undefined ? "LIMIT -1 " : "";
|
|
20
|
+
return `${limitSql}OFFSET ${offset}`;
|
|
21
|
+
}
|
|
22
|
+
compileDateWhere(type, column, operator, value) {
|
|
23
|
+
switch (type) {
|
|
24
|
+
case "date":
|
|
25
|
+
return `date(${column}) ${operator} ${this.escape(value)}`;
|
|
26
|
+
case "day":
|
|
27
|
+
return `CAST(strftime('%d', ${column}) AS INTEGER) ${operator} ${this.escape(value)}`;
|
|
28
|
+
case "month":
|
|
29
|
+
return `CAST(strftime('%m', ${column}) AS INTEGER) ${operator} ${this.escape(value)}`;
|
|
30
|
+
case "year":
|
|
31
|
+
return `CAST(strftime('%Y', ${column}) AS INTEGER) ${operator} ${this.escape(value)}`;
|
|
32
|
+
case "time":
|
|
33
|
+
return `time(${column}) ${operator} ${this.escape(value)}`;
|
|
34
|
+
default:
|
|
35
|
+
return `${column} ${operator} ${this.escape(value)}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
compileInsertOrIgnore(table, columns, values) {
|
|
39
|
+
return `INSERT OR IGNORE INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")}`;
|
|
40
|
+
}
|
|
41
|
+
compileUpsert(table, columns, values, uniqueBy, updateColumns) {
|
|
42
|
+
const updateCols = updateColumns
|
|
43
|
+
.map((c) => `${this.wrap(c)} = excluded.${this.wrap(c)}`)
|
|
44
|
+
.join(", ");
|
|
45
|
+
return `INSERT INTO ${table} (${columns.map((c) => this.wrap(c)).join(", ")}) VALUES ${values.join(", ")} ON CONFLICT(${uniqueBy.map((c) => this.wrap(c)).join(", ")}) DO UPDATE SET ${updateCols}`;
|
|
46
|
+
}
|
|
47
|
+
compileJsonContains(column, value) {
|
|
48
|
+
return `${column} IN (SELECT value FROM json_each(${column})) AND ${this.escape(value)} IN (SELECT value FROM json_each(${column}))`;
|
|
49
|
+
}
|
|
50
|
+
compileJsonLength(column, operator, value) {
|
|
51
|
+
return `(SELECT COUNT(*) FROM json_each(${column})) ${operator} ${this.escape(value)}`;
|
|
52
|
+
}
|
|
53
|
+
compileRegexp(column, value, not) {
|
|
54
|
+
const op = not ? "NOT REGEXP" : "REGEXP";
|
|
55
|
+
return `${column} ${op} ${this.escape(value)}`;
|
|
56
|
+
}
|
|
57
|
+
compileFullText(columns, value) {
|
|
58
|
+
return columns.map((c) => `${this.wrap(c)} LIKE ${this.escape(`%${value}%`)}`).join(" OR ");
|
|
59
|
+
}
|
|
60
|
+
compileExplain(sql) {
|
|
61
|
+
return `EXPLAIN QUERY PLAN ${sql}`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -2,16 +2,21 @@ import { Blueprint } from "./Blueprint.js";
|
|
|
2
2
|
import { SQLiteGrammar } from "./grammars/SQLiteGrammar.js";
|
|
3
3
|
import { MySqlGrammar } from "./grammars/MySqlGrammar.js";
|
|
4
4
|
import { PostgresGrammar } from "./grammars/PostgresGrammar.js";
|
|
5
|
+
import { ConnectionManager } from "../connection/ConnectionManager.js";
|
|
6
|
+
import { TenantContext } from "../connection/TenantContext.js";
|
|
5
7
|
export class Schema {
|
|
6
8
|
static connection;
|
|
7
9
|
static setConnection(connection) {
|
|
8
10
|
this.connection = connection;
|
|
11
|
+
ConnectionManager.setDefault(connection);
|
|
9
12
|
}
|
|
10
13
|
static getConnection() {
|
|
11
|
-
|
|
14
|
+
const tenantConnection = TenantContext.current()?.connection;
|
|
15
|
+
const connection = tenantConnection || this.connection || ConnectionManager.getDefault();
|
|
16
|
+
if (!connection) {
|
|
12
17
|
throw new Error("No database connection set.");
|
|
13
18
|
}
|
|
14
|
-
return
|
|
19
|
+
return connection;
|
|
15
20
|
}
|
|
16
21
|
static getGrammar() {
|
|
17
22
|
const driver = this.getConnection().getDriverName();
|
|
@@ -28,9 +33,10 @@ export class Schema {
|
|
|
28
33
|
const blueprint = new Blueprint(table);
|
|
29
34
|
callback(blueprint);
|
|
30
35
|
const grammar = this.getGrammar();
|
|
31
|
-
const
|
|
36
|
+
const connection = this.getConnection();
|
|
37
|
+
const sql = grammar.compileCreate(blueprint, connection.qualifyTable(table));
|
|
32
38
|
await this.getConnection().run(sql);
|
|
33
|
-
const indexes = grammar.compileIndexes(blueprint, table);
|
|
39
|
+
const indexes = grammar.compileIndexes(blueprint, connection.qualifyTable(table));
|
|
34
40
|
for (const indexSql of indexes) {
|
|
35
41
|
await this.getConnection().run(indexSql);
|
|
36
42
|
}
|
|
@@ -39,9 +45,10 @@ export class Schema {
|
|
|
39
45
|
const blueprint = new Blueprint(table);
|
|
40
46
|
callback(blueprint);
|
|
41
47
|
const grammar = this.getGrammar();
|
|
42
|
-
const
|
|
48
|
+
const connection = this.getConnection();
|
|
49
|
+
const sql = grammar.compileCreateIfNotExists(blueprint, connection.qualifyTable(table));
|
|
43
50
|
await this.getConnection().run(sql);
|
|
44
|
-
const indexes = grammar.compileIndexes(blueprint, table);
|
|
51
|
+
const indexes = grammar.compileIndexes(blueprint, connection.qualifyTable(table));
|
|
45
52
|
for (const indexSql of indexes) {
|
|
46
53
|
await this.getConnection().run(indexSql);
|
|
47
54
|
}
|
|
@@ -50,9 +57,11 @@ export class Schema {
|
|
|
50
57
|
const blueprint = new Blueprint(table);
|
|
51
58
|
callback(blueprint);
|
|
52
59
|
const grammar = this.getGrammar();
|
|
60
|
+
const connection = this.getConnection();
|
|
61
|
+
const qualifiedTable = connection.qualifyTable(table);
|
|
53
62
|
for (const command of blueprint.commands) {
|
|
54
63
|
if (command.name === "dropColumn") {
|
|
55
|
-
const sql = grammar.compileDropColumn(
|
|
64
|
+
const sql = grammar.compileDropColumn(qualifiedTable, command.parameters.column);
|
|
56
65
|
if (Array.isArray(sql)) {
|
|
57
66
|
for (const s of sql)
|
|
58
67
|
await this.getConnection().run(s);
|
|
@@ -62,7 +71,7 @@ export class Schema {
|
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
else if (command.name === "renameColumn") {
|
|
65
|
-
const sql = grammar.compileColumnRename(
|
|
74
|
+
const sql = grammar.compileColumnRename(qualifiedTable, command.parameters.from, command.parameters.to);
|
|
66
75
|
await this.getConnection().run(sql);
|
|
67
76
|
}
|
|
68
77
|
else if (command.name === "dropIndex") {
|
|
@@ -75,33 +84,38 @@ export class Schema {
|
|
|
75
84
|
await this.getConnection().run(`ALTER TABLE ${grammar.wrap(table)} DROP CONSTRAINT ${grammar.wrap(command.parameters.name)}`);
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
|
-
const addSqls = grammar.compileAdd(blueprint,
|
|
87
|
+
const addSqls = grammar.compileAdd(blueprint, qualifiedTable);
|
|
79
88
|
for (const sql of addSqls) {
|
|
80
89
|
await this.getConnection().run(sql);
|
|
81
90
|
}
|
|
82
|
-
const indexes = grammar.compileIndexes(blueprint,
|
|
91
|
+
const indexes = grammar.compileIndexes(blueprint, qualifiedTable);
|
|
83
92
|
for (const indexSql of indexes) {
|
|
84
93
|
await this.getConnection().run(indexSql);
|
|
85
94
|
}
|
|
86
|
-
const fks = grammar.compileForeignKeys(blueprint,
|
|
95
|
+
const fks = grammar.compileForeignKeys(blueprint, qualifiedTable);
|
|
87
96
|
for (const fkSql of fks) {
|
|
88
97
|
await this.getConnection().run(fkSql);
|
|
89
98
|
}
|
|
90
99
|
}
|
|
91
100
|
static async drop(table) {
|
|
92
101
|
const grammar = this.getGrammar();
|
|
93
|
-
|
|
102
|
+
const connection = this.getConnection();
|
|
103
|
+
await connection.run(grammar.compileDrop(connection.qualifyTable(table)));
|
|
94
104
|
}
|
|
95
105
|
static async dropIfExists(table) {
|
|
96
106
|
const grammar = this.getGrammar();
|
|
97
|
-
|
|
107
|
+
const connection = this.getConnection();
|
|
108
|
+
await connection.run(grammar.compileDropIfExists(connection.qualifyTable(table)));
|
|
98
109
|
}
|
|
99
110
|
static async rename(from, to) {
|
|
100
111
|
const grammar = this.getGrammar();
|
|
101
|
-
|
|
112
|
+
const connection = this.getConnection();
|
|
113
|
+
await connection.run(grammar.compileRename(connection.qualifyTable(from), connection.qualifyTable(to)));
|
|
102
114
|
}
|
|
103
115
|
static async hasTable(table) {
|
|
104
|
-
const
|
|
116
|
+
const connection = this.getConnection();
|
|
117
|
+
const driver = connection.getDriverName();
|
|
118
|
+
const schema = connection.getSchema() || "public";
|
|
105
119
|
let sql;
|
|
106
120
|
if (driver === "sqlite") {
|
|
107
121
|
sql = `SELECT name FROM sqlite_master WHERE type='table' AND name='${table}'`;
|
|
@@ -110,41 +124,45 @@ export class Schema {
|
|
|
110
124
|
sql = `SHOW TABLES LIKE '${table}'`;
|
|
111
125
|
}
|
|
112
126
|
else {
|
|
113
|
-
sql = `SELECT * FROM information_schema.tables WHERE table_name = '${table}'`;
|
|
127
|
+
sql = `SELECT * FROM information_schema.tables WHERE table_schema = '${schema}' AND table_name = '${table}'`;
|
|
114
128
|
}
|
|
115
|
-
const result = await
|
|
129
|
+
const result = await connection.query(sql);
|
|
116
130
|
return result.length > 0;
|
|
117
131
|
}
|
|
118
132
|
static async hasColumn(table, column) {
|
|
119
|
-
const
|
|
133
|
+
const connection = this.getConnection();
|
|
134
|
+
const driver = connection.getDriverName();
|
|
135
|
+
const schema = connection.getSchema() || "public";
|
|
120
136
|
let sql;
|
|
121
137
|
if (driver === "sqlite") {
|
|
122
138
|
sql = `PRAGMA table_info(${table})`;
|
|
123
|
-
const result = await
|
|
139
|
+
const result = await connection.query(sql);
|
|
124
140
|
return result.some((row) => row.name === column);
|
|
125
141
|
}
|
|
126
142
|
else if (driver === "mysql") {
|
|
127
143
|
sql = `SHOW COLUMNS FROM ${table} LIKE '${column}'`;
|
|
128
144
|
}
|
|
129
145
|
else {
|
|
130
|
-
sql = `SELECT column_name FROM information_schema.columns WHERE table_name = '${table}' AND column_name = '${column}'`;
|
|
146
|
+
sql = `SELECT column_name FROM information_schema.columns WHERE table_schema = '${schema}' AND table_name = '${table}' AND column_name = '${column}'`;
|
|
131
147
|
}
|
|
132
|
-
const result = await
|
|
148
|
+
const result = await connection.query(sql);
|
|
133
149
|
return result.length > 0;
|
|
134
150
|
}
|
|
135
151
|
static async getColumn(table, column) {
|
|
136
|
-
const
|
|
152
|
+
const connection = this.getConnection();
|
|
153
|
+
const driver = connection.getDriverName();
|
|
154
|
+
const schema = connection.getSchema() || "public";
|
|
137
155
|
if (driver === "sqlite") {
|
|
138
|
-
const rows = await
|
|
156
|
+
const rows = await connection.query(`PRAGMA table_info(${table})`);
|
|
139
157
|
const row = rows.find((item) => item.name === column);
|
|
140
158
|
return row ? { name: row.name, type: row.type, primary: row.pk > 0, autoIncrement: false } : null;
|
|
141
159
|
}
|
|
142
160
|
if (driver === "mysql") {
|
|
143
|
-
const rows = await
|
|
161
|
+
const rows = await connection.query(`SHOW COLUMNS FROM ${table} LIKE '${column}'`);
|
|
144
162
|
const row = rows[0];
|
|
145
163
|
return row ? { name: row.Field, type: row.Type, primary: row.Key === "PRI", autoIncrement: String(row.Extra || "").toLowerCase().includes("auto_increment") } : null;
|
|
146
164
|
}
|
|
147
|
-
const rows = await
|
|
165
|
+
const rows = await connection.query(`SELECT c.column_name, c.data_type, COALESCE(tc.constraint_type = 'PRIMARY KEY', false) AS primary_key
|
|
148
166
|
FROM information_schema.columns c
|
|
149
167
|
LEFT JOIN information_schema.key_column_usage kcu
|
|
150
168
|
ON c.table_schema = kcu.table_schema
|
|
@@ -153,7 +171,7 @@ export class Schema {
|
|
|
153
171
|
LEFT JOIN information_schema.table_constraints tc
|
|
154
172
|
ON kcu.table_schema = tc.table_schema
|
|
155
173
|
AND kcu.constraint_name = tc.constraint_name
|
|
156
|
-
WHERE c.table_schema = '
|
|
174
|
+
WHERE c.table_schema = '${schema}'
|
|
157
175
|
AND c.table_name = '${table}'
|
|
158
176
|
AND c.column_name = '${column}'`);
|
|
159
177
|
const row = rows[0];
|
|
@@ -119,7 +119,8 @@ export class TypeGenerator {
|
|
|
119
119
|
sql = "SHOW TABLES";
|
|
120
120
|
}
|
|
121
121
|
else {
|
|
122
|
-
|
|
122
|
+
const schema = this.connection.getSchema() || "public";
|
|
123
|
+
sql = `SELECT table_name FROM information_schema.tables WHERE table_schema = '${schema}' AND table_type = 'BASE TABLE'`;
|
|
123
124
|
}
|
|
124
125
|
const rows = await this.connection.query(sql);
|
|
125
126
|
if (driver === "sqlite") {
|
|
@@ -174,7 +175,8 @@ export class TypeGenerator {
|
|
|
174
175
|
}));
|
|
175
176
|
}
|
|
176
177
|
// postgres
|
|
177
|
-
const
|
|
178
|
+
const schema = this.connection.getSchema() || "public";
|
|
179
|
+
const rows = await this.connection.query(`SELECT column_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_name = '${table}' AND table_schema = '${schema}' ORDER BY ordinal_position`);
|
|
178
180
|
return rows.map((r) => ({
|
|
179
181
|
name: r.column_name,
|
|
180
182
|
type: r.data_type,
|
|
@@ -40,8 +40,17 @@ export interface OrderClause {
|
|
|
40
40
|
column: string;
|
|
41
41
|
direction: "asc" | "desc";
|
|
42
42
|
}
|
|
43
|
+
export interface HavingClause {
|
|
44
|
+
sql: string;
|
|
45
|
+
boolean: "and" | "or";
|
|
46
|
+
}
|
|
47
|
+
export interface UnionClause {
|
|
48
|
+
query: string;
|
|
49
|
+
all: boolean;
|
|
50
|
+
}
|
|
43
51
|
export type ConnectionConfig = {
|
|
44
52
|
url: string;
|
|
53
|
+
schema?: string;
|
|
45
54
|
} | {
|
|
46
55
|
driver: "sqlite" | "mysql" | "postgres";
|
|
47
56
|
host?: string;
|
|
@@ -50,4 +59,5 @@ export type ConnectionConfig = {
|
|
|
50
59
|
username?: string;
|
|
51
60
|
password?: string;
|
|
52
61
|
filename?: string;
|
|
62
|
+
schema?: string;
|
|
53
63
|
};
|
package/package.json
CHANGED