@jskit-ai/database-runtime 0.1.11 → 0.1.13
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/package.descriptor.mjs +2 -2
- package/package.json +2 -2
- package/src/server/providers/DatabaseRuntimeServiceProvider.js +6 -23
- package/src/shared/databaseConnection.js +116 -0
- package/src/shared/index.js +5 -0
- package/templates/knexfile.js +9 -27
- package/test/databaseConnection.test.js +60 -0
- package/test/providerRuntime.test.js +65 -38
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/database-runtime",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.13",
|
|
5
5
|
dependsOn: [
|
|
6
6
|
"@jskit-ai/kernel"
|
|
7
7
|
],
|
|
@@ -55,7 +55,7 @@ export default Object.freeze({
|
|
|
55
55
|
mutations: {
|
|
56
56
|
dependencies: {
|
|
57
57
|
runtime: {
|
|
58
|
-
"@jskit-ai/kernel": "0.1.
|
|
58
|
+
"@jskit-ai/kernel": "0.1.12",
|
|
59
59
|
"dotenv": "^16.4.5",
|
|
60
60
|
"knex": "^3.1.0"
|
|
61
61
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/database-runtime",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
"./shared/transactions": "./src/shared/transactions.js"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@jskit-ai/kernel": "0.1.
|
|
28
|
+
"@jskit-ai/kernel": "0.1.12"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
normalizeDatabaseClient,
|
|
8
8
|
toKnexClientId
|
|
9
9
|
} from "../../shared/databaseClient.js";
|
|
10
|
+
import { resolveDatabaseConnectionFromEnvironment } from "../../shared/databaseConnection.js";
|
|
10
11
|
|
|
11
12
|
const DATABASE_RUNTIME_TOKEN = "runtime.database";
|
|
12
13
|
const DATABASE_DRIVER_TOKEN = "runtime.database.driver";
|
|
@@ -42,22 +43,6 @@ function resolveDriverDialectId(driver) {
|
|
|
42
43
|
return "";
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
function resolveRequiredEnvString(env, key) {
|
|
46
|
-
const value = normalizeText(env?.[key]);
|
|
47
|
-
if (!value) {
|
|
48
|
-
throw new Error(`${key} is required for database runtime.`);
|
|
49
|
-
}
|
|
50
|
-
return value;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function resolvePort(value, fallbackPort) {
|
|
54
|
-
const parsed = Number.parseInt(normalizeText(value), 10);
|
|
55
|
-
if (Number.isInteger(parsed) && parsed > 0) {
|
|
56
|
-
return parsed;
|
|
57
|
-
}
|
|
58
|
-
return fallbackPort;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
46
|
function loadKnexFactory() {
|
|
62
47
|
let moduleValue;
|
|
63
48
|
try {
|
|
@@ -142,16 +127,14 @@ function createKnexConfig(scope) {
|
|
|
142
127
|
|
|
143
128
|
const client = toKnexClientId(dialectId);
|
|
144
129
|
const defaultPort = dialectId === "pg" ? 5432 : 3306;
|
|
130
|
+
const connection = resolveDatabaseConnectionFromEnvironment(env, {
|
|
131
|
+
defaultPort,
|
|
132
|
+
context: "database runtime"
|
|
133
|
+
});
|
|
145
134
|
|
|
146
135
|
return {
|
|
147
136
|
client,
|
|
148
|
-
connection
|
|
149
|
-
host: normalizeText(env.DB_HOST) || "localhost",
|
|
150
|
-
port: resolvePort(env.DB_PORT, defaultPort),
|
|
151
|
-
database: resolveRequiredEnvString(env, "DB_NAME"),
|
|
152
|
-
user: resolveRequiredEnvString(env, "DB_USER"),
|
|
153
|
-
password: String(env.DB_PASSWORD ?? "")
|
|
154
|
-
}
|
|
137
|
+
connection
|
|
155
138
|
};
|
|
156
139
|
}
|
|
157
140
|
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { normalizeDatabaseClient, normalizeText } from "./databaseClient.js";
|
|
2
|
+
|
|
3
|
+
const DATABASE_URL_PROTOCOL_TO_CLIENT = Object.freeze({
|
|
4
|
+
"mysql:": "mysql2",
|
|
5
|
+
"mysql2:": "mysql2",
|
|
6
|
+
"mariadb:": "mysql2",
|
|
7
|
+
"postgres:": "pg",
|
|
8
|
+
"postgresql:": "pg",
|
|
9
|
+
"pg:": "pg"
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
function toPositiveInteger(value, fallback) {
|
|
13
|
+
const parsed = Number.parseInt(normalizeText(value), 10);
|
|
14
|
+
if (Number.isInteger(parsed) && parsed > 0) {
|
|
15
|
+
return parsed;
|
|
16
|
+
}
|
|
17
|
+
return fallback;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseDatabaseUrl(databaseUrl, { context = "DATABASE_URL", allowEmpty = false } = {}) {
|
|
21
|
+
const normalized = normalizeText(databaseUrl);
|
|
22
|
+
if (!normalized) {
|
|
23
|
+
if (allowEmpty) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`${context} is required.`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = new URL(normalized);
|
|
32
|
+
} catch {
|
|
33
|
+
throw new Error(`${context} must be a valid absolute URL.`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const databaseName = normalizeText(decodeURIComponent(String(parsed.pathname || "").replace(/^\/+/, "")));
|
|
37
|
+
const user = normalizeText(decodeURIComponent(parsed.username || ""));
|
|
38
|
+
const password = decodeURIComponent(parsed.password || "");
|
|
39
|
+
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
protocol: normalizeText(parsed.protocol).toLowerCase(),
|
|
42
|
+
host: normalizeText(parsed.hostname),
|
|
43
|
+
port: toPositiveInteger(parsed.port, 0),
|
|
44
|
+
database: databaseName,
|
|
45
|
+
user,
|
|
46
|
+
password
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function resolveDatabaseClientFromEnvironment(env = {}, { allowEmpty = false } = {}) {
|
|
51
|
+
const source = env && typeof env === "object" ? env : {};
|
|
52
|
+
const explicitClient = normalizeText(source.DB_CLIENT);
|
|
53
|
+
if (explicitClient) {
|
|
54
|
+
return normalizeDatabaseClient(explicitClient, { allowEmpty });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parsedUrl = parseDatabaseUrl(source.DATABASE_URL, { allowEmpty: true });
|
|
58
|
+
const inferredClient = parsedUrl ? DATABASE_URL_PROTOCOL_TO_CLIENT[parsedUrl.protocol] || "" : "";
|
|
59
|
+
if (inferredClient) {
|
|
60
|
+
return normalizeDatabaseClient(inferredClient, { allowEmpty });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (allowEmpty) {
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (parsedUrl) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Unsupported DATABASE_URL protocol "${parsedUrl.protocol}". Use one of: mysql, mysql2, mariadb, postgres, postgresql, pg.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
throw new Error("DB_CLIENT is required. Set DB_CLIENT or DATABASE_URL.");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function resolveDatabaseConnectionFromEnvironment(
|
|
77
|
+
env = {},
|
|
78
|
+
{
|
|
79
|
+
defaultHost = "localhost",
|
|
80
|
+
defaultPort = 3306,
|
|
81
|
+
context = "database runtime"
|
|
82
|
+
} = {}
|
|
83
|
+
) {
|
|
84
|
+
const source = env && typeof env === "object" ? env : {};
|
|
85
|
+
const parsedUrl = parseDatabaseUrl(source.DATABASE_URL, { allowEmpty: true });
|
|
86
|
+
|
|
87
|
+
const host = normalizeText(source.DB_HOST) || normalizeText(parsedUrl?.host) || defaultHost;
|
|
88
|
+
const port = toPositiveInteger(source.DB_PORT, parsedUrl?.port || defaultPort);
|
|
89
|
+
|
|
90
|
+
const database = normalizeText(source.DB_NAME) || normalizeText(parsedUrl?.database);
|
|
91
|
+
if (!database) {
|
|
92
|
+
throw new Error(`DB_NAME is required for ${context}. Set DB_NAME or DATABASE_URL.`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const user = normalizeText(source.DB_USER) || normalizeText(parsedUrl?.user);
|
|
96
|
+
if (!user) {
|
|
97
|
+
throw new Error(`DB_USER is required for ${context}. Set DB_USER or DATABASE_URL.`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const hasDbPassword = Object.prototype.hasOwnProperty.call(source, "DB_PASSWORD");
|
|
101
|
+
const password = hasDbPassword ? String(source.DB_PASSWORD ?? "") : String(parsedUrl?.password || "");
|
|
102
|
+
|
|
103
|
+
return Object.freeze({
|
|
104
|
+
host,
|
|
105
|
+
port,
|
|
106
|
+
database,
|
|
107
|
+
user,
|
|
108
|
+
password
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
parseDatabaseUrl,
|
|
114
|
+
resolveDatabaseClientFromEnvironment,
|
|
115
|
+
resolveDatabaseConnectionFromEnvironment
|
|
116
|
+
};
|
package/src/shared/index.js
CHANGED
|
@@ -15,6 +15,11 @@ export {
|
|
|
15
15
|
} from "./dateUtils.js";
|
|
16
16
|
export { normalizeDialect, detectDialectFromClient } from "./dialect.js";
|
|
17
17
|
export { normalizeText, normalizeDatabaseClient, toKnexClientId } from "./databaseClient.js";
|
|
18
|
+
export {
|
|
19
|
+
parseDatabaseUrl,
|
|
20
|
+
resolveDatabaseClientFromEnvironment,
|
|
21
|
+
resolveDatabaseConnectionFromEnvironment
|
|
22
|
+
} from "./databaseConnection.js";
|
|
18
23
|
export { isDuplicateEntryError } from "./duplicateEntry.js";
|
|
19
24
|
export { normalizePath, jsonTextExpression, whereJsonTextEquals } from "./json.js";
|
|
20
25
|
export { DEFAULT_VISIBILITY_COLUMNS, applyVisibility, applyVisibilityOwners } from "./visibility.js";
|
package/templates/knexfile.js
CHANGED
|
@@ -2,25 +2,10 @@ import path from "node:path";
|
|
|
2
2
|
import dotenv from "dotenv";
|
|
3
3
|
import {
|
|
4
4
|
normalizeText,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function resolveRequiredEnvString(env, key) {
|
|
10
|
-
const value = normalizeText(env[key]);
|
|
11
|
-
if (!value) {
|
|
12
|
-
throw new Error(`${key} is required.`);
|
|
13
|
-
}
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function resolvePort(value, fallbackPort) {
|
|
18
|
-
const parsed = Number.parseInt(normalizeText(value), 10);
|
|
19
|
-
if (Number.isInteger(parsed) && parsed > 0) {
|
|
20
|
-
return parsed;
|
|
21
|
-
}
|
|
22
|
-
return fallbackPort;
|
|
23
|
-
}
|
|
5
|
+
toKnexClientId,
|
|
6
|
+
resolveDatabaseClientFromEnvironment,
|
|
7
|
+
resolveDatabaseConnectionFromEnvironment
|
|
8
|
+
} from "@jskit-ai/database-runtime/shared";
|
|
24
9
|
|
|
25
10
|
const appRoot = process.cwd();
|
|
26
11
|
dotenv.config({
|
|
@@ -28,20 +13,17 @@ dotenv.config({
|
|
|
28
13
|
quiet: true
|
|
29
14
|
});
|
|
30
15
|
|
|
31
|
-
const dialectId =
|
|
16
|
+
const dialectId = resolveDatabaseClientFromEnvironment(process.env);
|
|
32
17
|
const client = toKnexClientId(dialectId);
|
|
33
18
|
const defaultPort = dialectId === "pg" ? 5432 : 3306;
|
|
34
19
|
const migrationsDirectory = path.resolve(appRoot, normalizeText(process.env.DB_MIGRATIONS_DIR) || "migrations");
|
|
35
20
|
|
|
36
21
|
export default {
|
|
37
22
|
client,
|
|
38
|
-
connection: {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
user: resolveRequiredEnvString(process.env, "DB_USER"),
|
|
43
|
-
password: String(process.env.DB_PASSWORD ?? "")
|
|
44
|
-
},
|
|
23
|
+
connection: resolveDatabaseConnectionFromEnvironment(process.env, {
|
|
24
|
+
defaultPort,
|
|
25
|
+
context: "knex migrations"
|
|
26
|
+
}),
|
|
45
27
|
migrations: {
|
|
46
28
|
directory: migrationsDirectory,
|
|
47
29
|
extension: "cjs"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
parseDatabaseUrl,
|
|
5
|
+
resolveDatabaseClientFromEnvironment,
|
|
6
|
+
resolveDatabaseConnectionFromEnvironment
|
|
7
|
+
} from "../src/shared/databaseConnection.js";
|
|
8
|
+
|
|
9
|
+
test("parseDatabaseUrl parses mysql url fields", () => {
|
|
10
|
+
const parsed = parseDatabaseUrl("mysql://appuser:apppass@db.local:3307/appdb");
|
|
11
|
+
assert.equal(parsed.protocol, "mysql:");
|
|
12
|
+
assert.equal(parsed.host, "db.local");
|
|
13
|
+
assert.equal(parsed.port, 3307);
|
|
14
|
+
assert.equal(parsed.database, "appdb");
|
|
15
|
+
assert.equal(parsed.user, "appuser");
|
|
16
|
+
assert.equal(parsed.password, "apppass");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("resolveDatabaseClientFromEnvironment infers client from DATABASE_URL when DB_CLIENT is absent", () => {
|
|
20
|
+
const client = resolveDatabaseClientFromEnvironment({
|
|
21
|
+
DATABASE_URL: "postgres://user:pass@db.local:5432/appdb"
|
|
22
|
+
});
|
|
23
|
+
assert.equal(client, "pg");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("resolveDatabaseConnectionFromEnvironment falls back to DATABASE_URL values", () => {
|
|
27
|
+
const connection = resolveDatabaseConnectionFromEnvironment({
|
|
28
|
+
DATABASE_URL: "mysql://urluser:urlpass@db.url.local:3308/url_db_name"
|
|
29
|
+
}, {
|
|
30
|
+
defaultPort: 3306,
|
|
31
|
+
context: "database runtime"
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
assert.equal(connection.host, "db.url.local");
|
|
35
|
+
assert.equal(connection.port, 3308);
|
|
36
|
+
assert.equal(connection.database, "url_db_name");
|
|
37
|
+
assert.equal(connection.user, "urluser");
|
|
38
|
+
assert.equal(connection.password, "urlpass");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("resolveDatabaseConnectionFromEnvironment keeps explicit DB_* values over DATABASE_URL", () => {
|
|
42
|
+
const connection = resolveDatabaseConnectionFromEnvironment({
|
|
43
|
+
DATABASE_URL: "mysql://urluser:urlpass@db.url.local:3308/url_db_name",
|
|
44
|
+
DB_HOST: "db.explicit.local",
|
|
45
|
+
DB_PORT: "3310",
|
|
46
|
+
DB_NAME: "explicit_db",
|
|
47
|
+
DB_USER: "explicit_user",
|
|
48
|
+
DB_PASSWORD: "explicit_pass"
|
|
49
|
+
}, {
|
|
50
|
+
defaultPort: 3306,
|
|
51
|
+
context: "database runtime"
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
assert.equal(connection.host, "db.explicit.local");
|
|
55
|
+
assert.equal(connection.port, 3310);
|
|
56
|
+
assert.equal(connection.database, "explicit_db");
|
|
57
|
+
assert.equal(connection.user, "explicit_user");
|
|
58
|
+
assert.equal(connection.password, "explicit_pass");
|
|
59
|
+
});
|
|
60
|
+
|
|
@@ -57,6 +57,47 @@ function createKnexStub() {
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
async function withAppRootKnexStub(callback) {
|
|
61
|
+
const appRoot = await mkdtemp(path.join(tmpdir(), "jskit-db-runtime-test-"));
|
|
62
|
+
const knexPackageDir = path.join(appRoot, "node_modules", "knex");
|
|
63
|
+
await mkdir(knexPackageDir, { recursive: true });
|
|
64
|
+
await writeFile(path.join(appRoot, "package.json"), JSON.stringify({ name: "runtime-app", private: true }), "utf8");
|
|
65
|
+
await writeFile(
|
|
66
|
+
path.join(knexPackageDir, "package.json"),
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
name: "knex",
|
|
69
|
+
version: "0.0.0-test",
|
|
70
|
+
main: "index.js",
|
|
71
|
+
type: "commonjs"
|
|
72
|
+
}),
|
|
73
|
+
"utf8"
|
|
74
|
+
);
|
|
75
|
+
await writeFile(
|
|
76
|
+
path.join(knexPackageDir, "index.js"),
|
|
77
|
+
[
|
|
78
|
+
"module.exports = function knex(config) {",
|
|
79
|
+
" return {",
|
|
80
|
+
" __source: 'app-root-knex',",
|
|
81
|
+
" __config: config,",
|
|
82
|
+
" transaction: async function transaction(callback) {",
|
|
83
|
+
" return callback({ trxId: 'trx-app-root' });",
|
|
84
|
+
" }",
|
|
85
|
+
" };",
|
|
86
|
+
"};",
|
|
87
|
+
""
|
|
88
|
+
].join("\n"),
|
|
89
|
+
"utf8"
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const previousCwd = process.cwd();
|
|
93
|
+
try {
|
|
94
|
+
process.chdir(appRoot);
|
|
95
|
+
await callback();
|
|
96
|
+
} finally {
|
|
97
|
+
process.chdir(previousCwd);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
60
101
|
test("DatabaseRuntimeServiceProvider registers runtime api", () => {
|
|
61
102
|
const app = createSingletonApp();
|
|
62
103
|
const provider = new DatabaseRuntimeServiceProvider();
|
|
@@ -112,41 +153,7 @@ test("DatabaseRuntimeServiceProvider driver token throws when multiple drivers a
|
|
|
112
153
|
});
|
|
113
154
|
|
|
114
155
|
test("DatabaseRuntimeServiceProvider resolves knex from app root package context", async () => {
|
|
115
|
-
|
|
116
|
-
const knexPackageDir = path.join(appRoot, "node_modules", "knex");
|
|
117
|
-
await mkdir(knexPackageDir, { recursive: true });
|
|
118
|
-
await writeFile(path.join(appRoot, "package.json"), JSON.stringify({ name: "runtime-app", private: true }), "utf8");
|
|
119
|
-
await writeFile(
|
|
120
|
-
path.join(knexPackageDir, "package.json"),
|
|
121
|
-
JSON.stringify({
|
|
122
|
-
name: "knex",
|
|
123
|
-
version: "0.0.0-test",
|
|
124
|
-
main: "index.js",
|
|
125
|
-
type: "commonjs"
|
|
126
|
-
}),
|
|
127
|
-
"utf8"
|
|
128
|
-
);
|
|
129
|
-
await writeFile(
|
|
130
|
-
path.join(knexPackageDir, "index.js"),
|
|
131
|
-
[
|
|
132
|
-
"module.exports = function knex(config) {",
|
|
133
|
-
" return {",
|
|
134
|
-
" __source: 'app-root-knex',",
|
|
135
|
-
" __config: config,",
|
|
136
|
-
" transaction: async function transaction(callback) {",
|
|
137
|
-
" return callback({ trxId: 'trx-app-root' });",
|
|
138
|
-
" }",
|
|
139
|
-
" };",
|
|
140
|
-
"};",
|
|
141
|
-
""
|
|
142
|
-
].join("\n"),
|
|
143
|
-
"utf8"
|
|
144
|
-
);
|
|
145
|
-
|
|
146
|
-
const previousCwd = process.cwd();
|
|
147
|
-
try {
|
|
148
|
-
process.chdir(appRoot);
|
|
149
|
-
|
|
156
|
+
await withAppRootKnexStub(async () => {
|
|
150
157
|
const app = createSingletonApp();
|
|
151
158
|
app.instance("runtime.database.driver.mysql", Object.freeze({ DIALECT_ID: "mysql2" }));
|
|
152
159
|
app.instance(KERNEL_TOKENS.Env, {
|
|
@@ -168,7 +175,27 @@ test("DatabaseRuntimeServiceProvider resolves knex from app root package context
|
|
|
168
175
|
assert.equal(knex.__config.connection.database, "appdb");
|
|
169
176
|
assert.equal(knex.__config.connection.user, "appuser");
|
|
170
177
|
assert.equal(knex.__config.connection.password, "apppass");
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("DatabaseRuntimeServiceProvider resolves knex config from DATABASE_URL when DB_* vars are omitted", async () => {
|
|
182
|
+
await withAppRootKnexStub(async () => {
|
|
183
|
+
const app = createSingletonApp();
|
|
184
|
+
app.instance("runtime.database.driver.mysql", Object.freeze({ DIALECT_ID: "mysql2" }));
|
|
185
|
+
app.instance(KERNEL_TOKENS.Env, {
|
|
186
|
+
DATABASE_URL: "mysql://urluser:urlpass@db.url.local:3308/url_db_name"
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const provider = new DatabaseRuntimeServiceProvider();
|
|
190
|
+
provider.register(app);
|
|
191
|
+
|
|
192
|
+
const knex = app.make(KERNEL_TOKENS.Knex);
|
|
193
|
+
assert.equal(knex.__source, "app-root-knex");
|
|
194
|
+
assert.equal(knex.__config.client, "mysql2");
|
|
195
|
+
assert.equal(knex.__config.connection.host, "db.url.local");
|
|
196
|
+
assert.equal(knex.__config.connection.port, 3308);
|
|
197
|
+
assert.equal(knex.__config.connection.database, "url_db_name");
|
|
198
|
+
assert.equal(knex.__config.connection.user, "urluser");
|
|
199
|
+
assert.equal(knex.__config.connection.password, "urlpass");
|
|
200
|
+
});
|
|
174
201
|
});
|