@dataramen/cli 0.0.9 → 0.0.10
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/README.md +67 -0
- package/dist/code/api/chat/router.js +55 -0
- package/dist/code/api/dataSources/router.js +147 -0
- package/dist/code/api/dataSources/types.js +2 -0
- package/dist/code/api/dataSources/validators.js +22 -0
- package/dist/code/api/project/router.js +100 -0
- package/dist/code/api/queries/router.js +122 -0
- package/dist/code/api/runner/router.js +22 -0
- package/dist/code/api/status/router.js +17 -0
- package/dist/code/api/teams/router.js +35 -0
- package/dist/code/api/userSettings/router.js +54 -0
- package/dist/code/api/users/router.js +91 -0
- package/dist/code/api/workbooks/router.js +123 -0
- package/dist/code/api/workbooks/types.js +2 -0
- package/dist/code/env.js +25 -0
- package/dist/code/index.js +86 -0
- package/dist/code/proxy.js +8 -8
- package/dist/code/repository/db.js +58 -0
- package/dist/code/repository/tables/databaseInspection.js +40 -0
- package/dist/code/repository/tables/datasource.js +86 -0
- package/dist/code/repository/tables/query.js +50 -0
- package/dist/code/repository/tables/teams.js +48 -0
- package/dist/code/repository/tables/userSettings.js +39 -0
- package/dist/code/repository/tables/users.js +42 -0
- package/dist/code/repository/tables/workbook.js +43 -0
- package/dist/code/services/connectorManager/index.js +38 -0
- package/dist/code/services/connectorManager/types.js +2 -0
- package/dist/code/services/files/index.js +44 -0
- package/dist/code/services/mysqlConnector/index.js +180 -0
- package/dist/code/services/oauthClient/oauth2Client.js +10 -0
- package/dist/code/services/openai/index.js +20 -0
- package/dist/code/services/openai/types.js +2 -0
- package/dist/code/services/pgConnector/index.js +220 -0
- package/dist/code/services/userSqlPromptRunner/index.js +207 -0
- package/dist/code/types/connectors.js +2 -0
- package/dist/code/utils/createRouter.js +10 -0
- package/dist/code/utils/httpError.js +13 -0
- package/dist/code/utils/prompts.js +11 -0
- package/dist/code/utils/queryUtils.js +18 -0
- package/dist/code/utils/rawSql.js +32 -0
- package/dist/code/utils/request.js +35 -0
- package/dist/code/utils/token.js +8 -0
- package/dist/package.json +1 -1
- package/package.json +21 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DatabaseInspection = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.DatabaseInspection = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "DatabaseInspection",
|
|
7
|
+
tableName: "db_inspection",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: String,
|
|
11
|
+
unique: true,
|
|
12
|
+
primary: true,
|
|
13
|
+
generated: "uuid",
|
|
14
|
+
},
|
|
15
|
+
tableName: {
|
|
16
|
+
nullable: true,
|
|
17
|
+
type: String,
|
|
18
|
+
},
|
|
19
|
+
columns: {
|
|
20
|
+
type: "json",
|
|
21
|
+
nullable: true,
|
|
22
|
+
},
|
|
23
|
+
createdAt: {
|
|
24
|
+
type: "datetime",
|
|
25
|
+
default: "CURRENT_TIMESTAMP",
|
|
26
|
+
},
|
|
27
|
+
updatedAt: {
|
|
28
|
+
type: "datetime",
|
|
29
|
+
default: "CURRENT_TIMESTAMP",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
relations: {
|
|
33
|
+
datasource: {
|
|
34
|
+
target: () => "DataSource",
|
|
35
|
+
type: "many-to-one",
|
|
36
|
+
joinTable: false,
|
|
37
|
+
cascade: true,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataSource = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.DataSource = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "DataSource",
|
|
7
|
+
tableName: "data_sources",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
dbUrl: {
|
|
15
|
+
type: String,
|
|
16
|
+
},
|
|
17
|
+
dbPort: {
|
|
18
|
+
type: Number,
|
|
19
|
+
nullable: true,
|
|
20
|
+
},
|
|
21
|
+
dbUser: {
|
|
22
|
+
type: String,
|
|
23
|
+
},
|
|
24
|
+
dbPassword: {
|
|
25
|
+
type: String,
|
|
26
|
+
nullable: true,
|
|
27
|
+
},
|
|
28
|
+
dbType: {
|
|
29
|
+
type: String,
|
|
30
|
+
},
|
|
31
|
+
createdAt: {
|
|
32
|
+
type: "datetime",
|
|
33
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
34
|
+
},
|
|
35
|
+
updatedAt: {
|
|
36
|
+
type: "datetime",
|
|
37
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
38
|
+
},
|
|
39
|
+
name: {
|
|
40
|
+
type: String,
|
|
41
|
+
},
|
|
42
|
+
description: {
|
|
43
|
+
type: String,
|
|
44
|
+
nullable: true,
|
|
45
|
+
},
|
|
46
|
+
dbDatabase: {
|
|
47
|
+
type: String,
|
|
48
|
+
},
|
|
49
|
+
dbSchema: {
|
|
50
|
+
type: String,
|
|
51
|
+
nullable: true,
|
|
52
|
+
},
|
|
53
|
+
lastInspected: {
|
|
54
|
+
type: "datetime",
|
|
55
|
+
nullable: true,
|
|
56
|
+
default: () => null,
|
|
57
|
+
},
|
|
58
|
+
status: {
|
|
59
|
+
type: String,
|
|
60
|
+
nullable: true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
relations: {
|
|
64
|
+
team: {
|
|
65
|
+
type: "many-to-one",
|
|
66
|
+
target: () => "Team",
|
|
67
|
+
inverseSide: "datasources",
|
|
68
|
+
joinColumn: true,
|
|
69
|
+
},
|
|
70
|
+
inspections: {
|
|
71
|
+
type: "one-to-many",
|
|
72
|
+
target: () => "DatabaseInspection",
|
|
73
|
+
inverseSide: "datasource",
|
|
74
|
+
},
|
|
75
|
+
queries: {
|
|
76
|
+
type: "one-to-many",
|
|
77
|
+
target: () => "Query",
|
|
78
|
+
inverseSide: "dataSource",
|
|
79
|
+
},
|
|
80
|
+
owner: {
|
|
81
|
+
type: "many-to-one",
|
|
82
|
+
target: () => "User",
|
|
83
|
+
joinColumn: true,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Query = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.Query = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "Query",
|
|
7
|
+
tableName: "query",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
name: {
|
|
15
|
+
type: String,
|
|
16
|
+
},
|
|
17
|
+
opts: {
|
|
18
|
+
type: "json",
|
|
19
|
+
default: "{}",
|
|
20
|
+
},
|
|
21
|
+
isTrash: {
|
|
22
|
+
type: Boolean,
|
|
23
|
+
default: false,
|
|
24
|
+
nullable: true,
|
|
25
|
+
},
|
|
26
|
+
createdAt: {
|
|
27
|
+
type: "datetime",
|
|
28
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
29
|
+
},
|
|
30
|
+
updatedAt: {
|
|
31
|
+
type: "datetime",
|
|
32
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
33
|
+
onUpdate: "CURRENT_TIMESTAMP",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
relations: {
|
|
37
|
+
team: {
|
|
38
|
+
type: "many-to-one",
|
|
39
|
+
target: () => "Team",
|
|
40
|
+
inverseSide: "workbooks",
|
|
41
|
+
joinColumn: true,
|
|
42
|
+
},
|
|
43
|
+
dataSource: {
|
|
44
|
+
type: "many-to-one",
|
|
45
|
+
target: () => "DataSource",
|
|
46
|
+
inverseSide: "queries",
|
|
47
|
+
joinColumn: true,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Team = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.Team = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "Team",
|
|
7
|
+
tableName: "teams",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
name: {
|
|
15
|
+
type: String,
|
|
16
|
+
},
|
|
17
|
+
createdAt: {
|
|
18
|
+
type: "datetime",
|
|
19
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
20
|
+
},
|
|
21
|
+
updatedAt: {
|
|
22
|
+
type: "datetime",
|
|
23
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
relations: {
|
|
27
|
+
users: {
|
|
28
|
+
type: "many-to-many",
|
|
29
|
+
target: () => "User",
|
|
30
|
+
inverseSide: "teams",
|
|
31
|
+
},
|
|
32
|
+
workbooks: {
|
|
33
|
+
type: "one-to-many",
|
|
34
|
+
target: () => "Workbook",
|
|
35
|
+
inverseSide: "team",
|
|
36
|
+
},
|
|
37
|
+
queries: {
|
|
38
|
+
type: "one-to-many",
|
|
39
|
+
target: () => "Query",
|
|
40
|
+
inverseSide: "team",
|
|
41
|
+
},
|
|
42
|
+
datasources: {
|
|
43
|
+
type: "one-to-many",
|
|
44
|
+
target: () => "DataSource",
|
|
45
|
+
inverseSide: "team",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UserSettings = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.UserSettings = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "UserSettings",
|
|
7
|
+
tableName: "user_settings",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
openAiToken: {
|
|
15
|
+
type: String,
|
|
16
|
+
nullable: true,
|
|
17
|
+
},
|
|
18
|
+
model: {
|
|
19
|
+
type: String,
|
|
20
|
+
default: "gpt-3.5-turbo",
|
|
21
|
+
},
|
|
22
|
+
createdAt: {
|
|
23
|
+
type: "datetime",
|
|
24
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
25
|
+
},
|
|
26
|
+
updatedAt: {
|
|
27
|
+
type: "datetime",
|
|
28
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
relations: {
|
|
32
|
+
user: {
|
|
33
|
+
type: "one-to-one",
|
|
34
|
+
target: () => "User",
|
|
35
|
+
inverseSide: "settings",
|
|
36
|
+
joinColumn: true,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.User = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.User = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "User",
|
|
7
|
+
tableName: "users",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
createdAt: {
|
|
15
|
+
type: "datetime",
|
|
16
|
+
default: "CURRENT_TIMESTAMP",
|
|
17
|
+
},
|
|
18
|
+
updatedAt: {
|
|
19
|
+
type: "datetime",
|
|
20
|
+
default: "CURRENT_TIMESTAMP",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
relations: {
|
|
24
|
+
teams: {
|
|
25
|
+
type: "many-to-many",
|
|
26
|
+
target: () => "Team",
|
|
27
|
+
inverseSide: "users",
|
|
28
|
+
joinTable: true,
|
|
29
|
+
},
|
|
30
|
+
settings: {
|
|
31
|
+
type: "one-to-one",
|
|
32
|
+
target: () => "UserSettings",
|
|
33
|
+
inverseSide: "user",
|
|
34
|
+
joinColumn: true,
|
|
35
|
+
},
|
|
36
|
+
currentTeam: {
|
|
37
|
+
type: "many-to-one",
|
|
38
|
+
target: () => "Team",
|
|
39
|
+
joinColumn: true,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Workbook = void 0;
|
|
4
|
+
const typeorm_1 = require("typeorm");
|
|
5
|
+
exports.Workbook = new typeorm_1.EntitySchema({
|
|
6
|
+
name: "Workbook",
|
|
7
|
+
tableName: "workbooks",
|
|
8
|
+
columns: {
|
|
9
|
+
id: {
|
|
10
|
+
type: "uuid",
|
|
11
|
+
primary: true,
|
|
12
|
+
generated: "uuid",
|
|
13
|
+
},
|
|
14
|
+
name: {
|
|
15
|
+
type: String,
|
|
16
|
+
},
|
|
17
|
+
path: {
|
|
18
|
+
type: "uuid",
|
|
19
|
+
generated: "uuid",
|
|
20
|
+
},
|
|
21
|
+
isTrash: {
|
|
22
|
+
type: "boolean",
|
|
23
|
+
default: false,
|
|
24
|
+
},
|
|
25
|
+
createdAt: {
|
|
26
|
+
type: "datetime",
|
|
27
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
28
|
+
},
|
|
29
|
+
updatedAt: {
|
|
30
|
+
type: "datetime",
|
|
31
|
+
default: () => "CURRENT_TIMESTAMP",
|
|
32
|
+
onUpdate: "CURRENT_TIMESTAMP",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
relations: {
|
|
36
|
+
team: {
|
|
37
|
+
type: "many-to-one",
|
|
38
|
+
target: () => "Team",
|
|
39
|
+
inverseSide: "workbooks",
|
|
40
|
+
joinColumn: true,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDynamicConnection = void 0;
|
|
4
|
+
const mysqlConnector_1 = require("../mysqlConnector");
|
|
5
|
+
const httpError_1 = require("../../utils/httpError");
|
|
6
|
+
const pgConnector_1 = require("../pgConnector");
|
|
7
|
+
const getDynamicConnection = async (datasource, req) => {
|
|
8
|
+
try {
|
|
9
|
+
let dbConnectionManager;
|
|
10
|
+
if (datasource.dbType === "mysql") {
|
|
11
|
+
dbConnectionManager = await (0, mysqlConnector_1.MySqlConnector)(datasource);
|
|
12
|
+
}
|
|
13
|
+
else if (datasource.dbType === "postgres") {
|
|
14
|
+
dbConnectionManager = await (0, pgConnector_1.PGSqlConnector)(datasource);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
throw new httpError_1.HttpError(500, `Connection manager for ${datasource.dbType} not found`);
|
|
18
|
+
}
|
|
19
|
+
if (!req.__connections) {
|
|
20
|
+
req.__connections = [dbConnectionManager];
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
req.__connections.push(dbConnectionManager);
|
|
24
|
+
}
|
|
25
|
+
return dbConnectionManager;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(error);
|
|
29
|
+
if (error instanceof httpError_1.HttpError) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if (error?.code === "ECONNREFUSED") {
|
|
33
|
+
throw new httpError_1.HttpError(500, "Failed to connect to the database");
|
|
34
|
+
}
|
|
35
|
+
throw new httpError_1.HttpError(500, error.message);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
exports.getDynamicConnection = getDynamicConnection;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.setupProjectFolders = exports.deleteFile = exports.storeFile = exports.getFile = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
+
const homeDir = node_os_1.default.homedir();
|
|
11
|
+
const filesPath = (0, node_path_1.join)(homeDir, ".dataramen", ".runtime", "files");
|
|
12
|
+
const getPath = (path) => {
|
|
13
|
+
return (0, node_path_1.join)(filesPath, path);
|
|
14
|
+
};
|
|
15
|
+
const getFile = async (path) => {
|
|
16
|
+
return promises_1.default.readFile(getPath(path), { encoding: "utf8" });
|
|
17
|
+
};
|
|
18
|
+
exports.getFile = getFile;
|
|
19
|
+
const storeFile = async (path, content) => {
|
|
20
|
+
return promises_1.default.writeFile(getPath(path), content, { encoding: "utf8" });
|
|
21
|
+
};
|
|
22
|
+
exports.storeFile = storeFile;
|
|
23
|
+
const deleteFile = async (path) => {
|
|
24
|
+
return promises_1.default.unlink(getPath(path));
|
|
25
|
+
};
|
|
26
|
+
exports.deleteFile = deleteFile;
|
|
27
|
+
const setupProjectFolders = async () => {
|
|
28
|
+
const hasFilesFolder = await filesFolderExists();
|
|
29
|
+
if (!hasFilesFolder) {
|
|
30
|
+
await promises_1.default.mkdir(filesPath, {
|
|
31
|
+
recursive: true
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
exports.setupProjectFolders = setupProjectFolders;
|
|
36
|
+
async function filesFolderExists() {
|
|
37
|
+
try {
|
|
38
|
+
const result = await promises_1.default.lstat(filesPath);
|
|
39
|
+
return result.isDirectory();
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MySqlConnector = void 0;
|
|
7
|
+
const promise_1 = __importDefault(require("mysql2/promise"));
|
|
8
|
+
const httpError_1 = require("../../utils/httpError");
|
|
9
|
+
const getConnection = ({ dbDatabase, dbPassword, dbUser, dbUrl }) => {
|
|
10
|
+
return promise_1.default.createConnection({
|
|
11
|
+
host: dbUrl,
|
|
12
|
+
user: dbUser,
|
|
13
|
+
database: dbDatabase,
|
|
14
|
+
password: dbPassword,
|
|
15
|
+
// TODO: timeout?
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
const extractPrimaryKeys = async (connection) => {
|
|
19
|
+
const query = `
|
|
20
|
+
SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION
|
|
21
|
+
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
|
|
22
|
+
WHERE CONSTRAINT_NAME = 'PRIMARY'
|
|
23
|
+
ORDER BY TABLE_NAME, ORDINAL_POSITION;
|
|
24
|
+
`;
|
|
25
|
+
const [rows] = await connection.execute(query);
|
|
26
|
+
const primaryKeysMap = {};
|
|
27
|
+
rows.forEach(row => {
|
|
28
|
+
const tableName = row.TABLE_NAME;
|
|
29
|
+
const columnName = row.COLUMN_NAME;
|
|
30
|
+
if (!primaryKeysMap[tableName]) {
|
|
31
|
+
primaryKeysMap[tableName] = [];
|
|
32
|
+
}
|
|
33
|
+
primaryKeysMap[tableName].push(columnName);
|
|
34
|
+
});
|
|
35
|
+
return primaryKeysMap;
|
|
36
|
+
};
|
|
37
|
+
const getReferences = async (connection) => {
|
|
38
|
+
const query = `
|
|
39
|
+
SELECT
|
|
40
|
+
TABLE_NAME AS table_name,
|
|
41
|
+
COLUMN_NAME AS field,
|
|
42
|
+
REFERENCED_TABLE_NAME AS referenced_table,
|
|
43
|
+
REFERENCED_COLUMN_NAME AS referenced_field
|
|
44
|
+
FROM
|
|
45
|
+
information_schema.KEY_COLUMN_USAGE
|
|
46
|
+
WHERE
|
|
47
|
+
REFERENCED_TABLE_NAME IS NOT NULL
|
|
48
|
+
AND CONSTRAINT_SCHEMA = DATABASE();
|
|
49
|
+
`;
|
|
50
|
+
const [rows] = await connection.execute(query);
|
|
51
|
+
const result = {};
|
|
52
|
+
if (Array.isArray(rows)) {
|
|
53
|
+
rows.forEach((row) => {
|
|
54
|
+
if (!result[row.table_name]) {
|
|
55
|
+
result[row.table_name] = {};
|
|
56
|
+
}
|
|
57
|
+
result[row.table_name][row.field] = {
|
|
58
|
+
refTable: row.referenced_table,
|
|
59
|
+
refField: row.referenced_field
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
const inspectSchema = async (dataSource, connection) => {
|
|
66
|
+
const result = await connection.query('SHOW TABLES');
|
|
67
|
+
const tables = result[0];
|
|
68
|
+
const refs = await getReferences(connection);
|
|
69
|
+
const primaryKeys = await extractPrimaryKeys(connection);
|
|
70
|
+
const rows = tables.map(async (table) => {
|
|
71
|
+
const tableName = Object.values(table)[0];
|
|
72
|
+
const inspectColumnsQuery = `select COLUMN_NAME, DATA_TYPE from information_schema.columns where table_schema = '${dataSource.dbDatabase}' and table_name = '${tableName}'`;
|
|
73
|
+
const [columns] = await connection.query(inspectColumnsQuery);
|
|
74
|
+
const ref = refs[tableName];
|
|
75
|
+
return {
|
|
76
|
+
columns: columns
|
|
77
|
+
.map((column) => ({
|
|
78
|
+
name: column.COLUMN_NAME,
|
|
79
|
+
type: column.DATA_TYPE,
|
|
80
|
+
isPrimary: primaryKeys[tableName]?.includes(column.COLUMN_NAME),
|
|
81
|
+
ref: ref?.[column.COLUMN_NAME] ? {
|
|
82
|
+
table: ref[column.COLUMN_NAME].refTable,
|
|
83
|
+
field: ref[column.COLUMN_NAME].refField,
|
|
84
|
+
} : undefined,
|
|
85
|
+
}))
|
|
86
|
+
.sort((col1, col2) => {
|
|
87
|
+
if (col1.isPrimary && col2.isPrimary) {
|
|
88
|
+
return col1.name.localeCompare(col2.name);
|
|
89
|
+
}
|
|
90
|
+
return col1.isPrimary ? -1 : 1;
|
|
91
|
+
}),
|
|
92
|
+
createdAt: new Date(),
|
|
93
|
+
tableName,
|
|
94
|
+
updatedAt: new Date(),
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
return Promise.all(rows);
|
|
98
|
+
};
|
|
99
|
+
const executeQuery = async (query, connection, opts) => {
|
|
100
|
+
try {
|
|
101
|
+
console.log(`[MYSQL CONN] Query: ${query}`);
|
|
102
|
+
const [result, columns] = await connection.query({
|
|
103
|
+
sql: query,
|
|
104
|
+
rowsAsArray: true,
|
|
105
|
+
});
|
|
106
|
+
const responseType = result?.constructor?.name;
|
|
107
|
+
if (responseType === "ResultSetHeader") {
|
|
108
|
+
// UPDATE, INSERT, DELETE
|
|
109
|
+
const resultSet = result;
|
|
110
|
+
if (resultSet.affectedRows > 3 && opts.allowBulkUpdate !== true) {
|
|
111
|
+
throw new Error(`[MYSQL CONN] Bulk update performed without permission.`);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
columns: [{ column: "affectedRows", alias: "Affected rows", full: "affectedRows" }],
|
|
115
|
+
rows: [[resultSet.affectedRows]],
|
|
116
|
+
query,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
else if (responseType === "Array") {
|
|
120
|
+
const rows = result; // todo: type
|
|
121
|
+
return {
|
|
122
|
+
columns: columns?.map((column) => ({
|
|
123
|
+
column: column.orgName || column.name,
|
|
124
|
+
table: column.orgTable,
|
|
125
|
+
alias: column.name,
|
|
126
|
+
full: column.orgTable ? column.orgTable + "." + column.orgName : column.name,
|
|
127
|
+
})) || [],
|
|
128
|
+
rows,
|
|
129
|
+
query,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
throw new Error(`[MYSQL CONN] Unknown result type: ${responseType}`);
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
console.error(e);
|
|
136
|
+
if (e instanceof httpError_1.HttpError) {
|
|
137
|
+
throw e;
|
|
138
|
+
}
|
|
139
|
+
throw new httpError_1.HttpError(400, e.message);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const withTransaction = async (connection, fn) => {
|
|
143
|
+
await connection.beginTransaction();
|
|
144
|
+
try {
|
|
145
|
+
const result = await fn();
|
|
146
|
+
await connection.commit();
|
|
147
|
+
console.log("[MYSQL CONN] Commit");
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
await connection.rollback();
|
|
152
|
+
console.warn(e.message);
|
|
153
|
+
console.log("[MYSQL CONN] Rollback");
|
|
154
|
+
throw e;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const MySqlConnector = async (dataSource) => {
|
|
158
|
+
const connection = await getConnection(dataSource);
|
|
159
|
+
let _isClosed = false;
|
|
160
|
+
return {
|
|
161
|
+
dbType: 'mysql',
|
|
162
|
+
dataSource,
|
|
163
|
+
inspectSchema: () => inspectSchema(dataSource, connection),
|
|
164
|
+
executeQuery: (query, opts) => {
|
|
165
|
+
if (opts.type === "SELECT") {
|
|
166
|
+
return executeQuery(query, connection, opts);
|
|
167
|
+
}
|
|
168
|
+
return withTransaction(connection, () => executeQuery(query, connection, opts));
|
|
169
|
+
},
|
|
170
|
+
checkConnection: async () => connection.ping(),
|
|
171
|
+
isClosed: () => _isClosed,
|
|
172
|
+
close: async () => {
|
|
173
|
+
if (_isClosed)
|
|
174
|
+
return;
|
|
175
|
+
_isClosed = true;
|
|
176
|
+
return connection.destroy();
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
exports.MySqlConnector = MySqlConnector;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTokenInfoFromRequest = void 0;
|
|
4
|
+
const getTokenInfoFromRequest = async (request) => {
|
|
5
|
+
return {
|
|
6
|
+
email: "local@localhost",
|
|
7
|
+
sub: "local",
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
exports.getTokenInfoFromRequest = getTokenInfoFromRequest;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executePrompt = void 0;
|
|
4
|
+
const URL = "https://api.openai.com/v1/chat/completions";
|
|
5
|
+
const executePrompt = async ({ openaiApiKey, messages, model, temperature }) => {
|
|
6
|
+
const request = await fetch(URL, {
|
|
7
|
+
method: "POST",
|
|
8
|
+
headers: {
|
|
9
|
+
"Content-Type": "application/json",
|
|
10
|
+
Authorization: `Bearer ${openaiApiKey}`,
|
|
11
|
+
},
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
messages,
|
|
14
|
+
model,
|
|
15
|
+
temperature,
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
return await request.json();
|
|
19
|
+
};
|
|
20
|
+
exports.executePrompt = executePrompt;
|