db-model-router 1.0.2 → 1.0.4
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 +317 -202
- package/docs/SKILL.md +250 -33
- package/docs/adapters/cockroachdb.md +1 -1
- package/docs/adapters/dynamodb.md +1 -1
- package/docs/adapters/mongodb.md +1 -1
- package/docs/adapters/mssql.md +1 -1
- package/docs/adapters/oracle.md +1 -1
- package/docs/adapters/postgres.md +1 -1
- package/docs/adapters/redis.md +1 -1
- package/docs/adapters/sqlite3.md +1 -1
- package/package.json +12 -6
- package/src/cli/commands/diff.js +114 -0
- package/src/cli/commands/doctor.js +181 -0
- package/src/cli/commands/generate-llm-docs.js +418 -0
- package/src/cli/commands/generate.js +240 -0
- package/src/cli/commands/help.js +180 -0
- package/src/cli/commands/init.js +181 -0
- package/src/cli/commands/inspect.js +222 -0
- package/src/cli/diff-engine.js +198 -0
- package/src/cli/flags.js +112 -0
- package/src/cli/generate-model.js +5 -4
- package/src/cli/generate-route.js +255 -14
- package/src/cli/init/dependencies.js +92 -0
- package/src/cli/init/generators.js +1791 -0
- package/src/cli/init/prompt.js +191 -0
- package/src/cli/init.js +404 -0
- package/src/cli/main.js +175 -0
- package/src/commons/model.js +5 -6
- package/src/commons/route.js +24 -0
- package/src/index.js +2 -0
- package/src/schema/schema-parser.js +78 -0
- package/src/schema/schema-printer.js +77 -0
- package/src/schema/schema-to-meta.js +78 -0
- package/src/schema/schema-validator.js +255 -0
- package/src/serve.js +5 -3
- package/docs/README.md +0 -208
- package/src/cli/generate-app.js +0 -359
|
@@ -25,10 +25,12 @@ function safeVarName(name) {
|
|
|
25
25
|
*/
|
|
26
26
|
function generateRouteFile(tableName, modelsRelPath) {
|
|
27
27
|
const varName = safeVarName(tableName);
|
|
28
|
-
return `
|
|
29
|
-
|
|
28
|
+
return `import dbModelRouter from "db-model-router";
|
|
29
|
+
import ${varName} from "${modelsRelPath}/${tableName}.js";
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
const { route } = dbModelRouter;
|
|
32
|
+
|
|
33
|
+
export default route(${varName});
|
|
32
34
|
`;
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -43,11 +45,13 @@ function generateChildRouteFile(
|
|
|
43
45
|
modelsRelPath,
|
|
44
46
|
) {
|
|
45
47
|
const varName = safeVarName(childTable);
|
|
46
|
-
return `
|
|
47
|
-
|
|
48
|
+
return `import dbModelRouter from "db-model-router";
|
|
49
|
+
import ${varName} from "${modelsRelPath}/${childTable}.js";
|
|
50
|
+
|
|
51
|
+
const { route } = dbModelRouter;
|
|
48
52
|
|
|
49
53
|
// Child route: scoped by parent ${parentTable} via ${fkColumn}
|
|
50
|
-
|
|
54
|
+
export default route(${varName}, { ${fkColumn}: "params.${fkColumn}" });
|
|
51
55
|
`;
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -56,7 +60,7 @@ module.exports = route(${varName}, { ${fkColumn}: "params.${fkColumn}" });
|
|
|
56
60
|
* Supports parent-child nesting: parent/:pk/child
|
|
57
61
|
*/
|
|
58
62
|
function generateRoutesIndexFile(tableNames, relationships = []) {
|
|
59
|
-
let imports = `
|
|
63
|
+
let imports = `import express from "express";\n\nconst router = express.Router();\n\n`;
|
|
60
64
|
|
|
61
65
|
// Collect child tables that are nested under parents
|
|
62
66
|
const nestedChildren = new Set();
|
|
@@ -66,12 +70,12 @@ function generateRoutesIndexFile(tableNames, relationships = []) {
|
|
|
66
70
|
|
|
67
71
|
for (const table of tableNames) {
|
|
68
72
|
const varName = safeVarName(table);
|
|
69
|
-
imports += `
|
|
73
|
+
imports += `import ${varName}Route from "./${table}.js";\n`;
|
|
70
74
|
}
|
|
71
75
|
// Import child routes with _child suffix for nested ones
|
|
72
76
|
for (const rel of relationships) {
|
|
73
77
|
const varName = safeVarName(rel.child);
|
|
74
|
-
imports += `
|
|
78
|
+
imports += `import ${varName}ChildRoute from "./${rel.child}_child_of_${rel.parent}.js";\n`;
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
imports += "\n";
|
|
@@ -85,9 +89,7 @@ function generateRoutesIndexFile(tableNames, relationships = []) {
|
|
|
85
89
|
|
|
86
90
|
// Mount nested child routes under parent
|
|
87
91
|
for (const rel of relationships) {
|
|
88
|
-
const parentVar = safeVarName(rel.parent);
|
|
89
92
|
const childVar = safeVarName(rel.child);
|
|
90
|
-
// Find parent PK from model file name convention — use fkColumn without _id suffix as parent pk param
|
|
91
93
|
imports += `router.use("/${rel.parent}/:${rel.fkColumn}/${rel.child}", ${childVar}ChildRoute);\n`;
|
|
92
94
|
}
|
|
93
95
|
|
|
@@ -97,7 +99,7 @@ function generateRoutesIndexFile(tableNames, relationships = []) {
|
|
|
97
99
|
imports += `router.use("/${rel.child}", ${varName}Route);\n`;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
imports += "\
|
|
102
|
+
imports += "\nexport default router;\n";
|
|
101
103
|
return imports;
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -108,6 +110,196 @@ function generateSimpleRoutesIndexFile(tableNames) {
|
|
|
108
110
|
return generateRoutesIndexFile(tableNames, []);
|
|
109
111
|
}
|
|
110
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Generate a test file for a route covering all CRUD methods.
|
|
115
|
+
* Uses supertest + the app's express setup.
|
|
116
|
+
*/
|
|
117
|
+
function generateTestFile(tableName, pk) {
|
|
118
|
+
const varName = safeVarName(tableName);
|
|
119
|
+
return `import assert from "assert";
|
|
120
|
+
import express from "express";
|
|
121
|
+
import request from "supertest";
|
|
122
|
+
import dbModelRouter from "db-model-router";
|
|
123
|
+
|
|
124
|
+
const { route } = dbModelRouter;
|
|
125
|
+
|
|
126
|
+
// Adjust the path to your model file as needed
|
|
127
|
+
import ${varName} from "../models/${tableName}.js";
|
|
128
|
+
|
|
129
|
+
function createApp() {
|
|
130
|
+
const app = express();
|
|
131
|
+
app.use(express.json());
|
|
132
|
+
app.use("/${tableName}", route(${varName}));
|
|
133
|
+
return app;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
describe("${tableName} routes", function () {
|
|
137
|
+
let app;
|
|
138
|
+
|
|
139
|
+
before(function () {
|
|
140
|
+
app = createApp();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe("GET /${tableName}/", function () {
|
|
144
|
+
it("should list records", async function () {
|
|
145
|
+
const res = await request(app).get("/${tableName}/");
|
|
146
|
+
assert.strictEqual(res.status, 200);
|
|
147
|
+
assert.ok(Array.isArray(res.body.data));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("POST /${tableName}/add", function () {
|
|
152
|
+
it("should insert a single record", async function () {
|
|
153
|
+
const res = await request(app)
|
|
154
|
+
.post("/${tableName}/add")
|
|
155
|
+
.send({});
|
|
156
|
+
assert.ok([200, 201, 400].includes(res.status));
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe("POST /${tableName}/", function () {
|
|
161
|
+
it("should bulk insert records", async function () {
|
|
162
|
+
const res = await request(app)
|
|
163
|
+
.post("/${tableName}/")
|
|
164
|
+
.send({ data: [] });
|
|
165
|
+
assert.ok([200, 201, 400].includes(res.status));
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("GET /${tableName}/:${pk}", function () {
|
|
170
|
+
it("should get a record by ID", async function () {
|
|
171
|
+
const res = await request(app).get("/${tableName}/1");
|
|
172
|
+
assert.ok([200, 404].includes(res.status));
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("PUT /${tableName}/:${pk}", function () {
|
|
177
|
+
it("should update a record", async function () {
|
|
178
|
+
const res = await request(app)
|
|
179
|
+
.put("/${tableName}/1")
|
|
180
|
+
.send({});
|
|
181
|
+
assert.ok([200, 400, 404].includes(res.status));
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("PATCH /${tableName}/:${pk}", function () {
|
|
186
|
+
it("should partially update a record", async function () {
|
|
187
|
+
const res = await request(app)
|
|
188
|
+
.patch("/${tableName}/1")
|
|
189
|
+
.send({});
|
|
190
|
+
assert.ok([200, 400, 404].includes(res.status));
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("DELETE /${tableName}/:${pk}", function () {
|
|
195
|
+
it("should delete a record", async function () {
|
|
196
|
+
const res = await request(app).delete("/${tableName}/1");
|
|
197
|
+
assert.ok([200, 204, 404].includes(res.status));
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("PUT /${tableName}/", function () {
|
|
202
|
+
it("should bulk update records", async function () {
|
|
203
|
+
const res = await request(app)
|
|
204
|
+
.put("/${tableName}/")
|
|
205
|
+
.send({ data: [] });
|
|
206
|
+
assert.ok([200, 400].includes(res.status));
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("DELETE /${tableName}/", function () {
|
|
211
|
+
it("should bulk delete records", async function () {
|
|
212
|
+
const res = await request(app)
|
|
213
|
+
.delete("/${tableName}/")
|
|
214
|
+
.send({});
|
|
215
|
+
assert.ok([200, 204, 400].includes(res.status));
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Generate a child route test file that tests the nested parent/:fk/child endpoints.
|
|
224
|
+
*/
|
|
225
|
+
function generateChildTestFile(childTable, parentTable, fkColumn, pk) {
|
|
226
|
+
const childVar = safeVarName(childTable);
|
|
227
|
+
return `import assert from "assert";
|
|
228
|
+
import express from "express";
|
|
229
|
+
import request from "supertest";
|
|
230
|
+
import dbModelRouter from "db-model-router";
|
|
231
|
+
|
|
232
|
+
const { route } = dbModelRouter;
|
|
233
|
+
|
|
234
|
+
import ${childVar} from "../models/${childTable}.js";
|
|
235
|
+
|
|
236
|
+
function createApp() {
|
|
237
|
+
const app = express();
|
|
238
|
+
app.use(express.json());
|
|
239
|
+
app.use("/${parentTable}/:${fkColumn}/${childTable}", route(${childVar}, { ${fkColumn}: "params.${fkColumn}" }));
|
|
240
|
+
return app;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
describe("${childTable} (child of ${parentTable}) routes", function () {
|
|
244
|
+
let app;
|
|
245
|
+
const parentId = 1;
|
|
246
|
+
|
|
247
|
+
before(function () {
|
|
248
|
+
app = createApp();
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
describe("GET /${parentTable}/:${fkColumn}/${childTable}/", function () {
|
|
252
|
+
it("should list child records scoped by parent", async function () {
|
|
253
|
+
const res = await request(app).get(\`/${parentTable}/\${parentId}/${childTable}/\`);
|
|
254
|
+
assert.strictEqual(res.status, 200);
|
|
255
|
+
assert.ok(Array.isArray(res.body.data));
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe("POST /${parentTable}/:${fkColumn}/${childTable}/add", function () {
|
|
260
|
+
it("should insert a child record", async function () {
|
|
261
|
+
const res = await request(app)
|
|
262
|
+
.post(\`/${parentTable}/\${parentId}/${childTable}/add\`)
|
|
263
|
+
.send({});
|
|
264
|
+
assert.ok([200, 201, 400].includes(res.status));
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
describe("GET /${parentTable}/:${fkColumn}/${childTable}/:${pk}", function () {
|
|
269
|
+
it("should get a child record by ID", async function () {
|
|
270
|
+
const res = await request(app).get(\`/${parentTable}/\${parentId}/${childTable}/1\`);
|
|
271
|
+
assert.ok([200, 404].includes(res.status));
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe("PUT /${parentTable}/:${fkColumn}/${childTable}/:${pk}", function () {
|
|
276
|
+
it("should update a child record", async function () {
|
|
277
|
+
const res = await request(app)
|
|
278
|
+
.put(\`/${parentTable}/\${parentId}/${childTable}/1\`)
|
|
279
|
+
.send({});
|
|
280
|
+
assert.ok([200, 400, 404].includes(res.status));
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
describe("PATCH /${parentTable}/:${fkColumn}/${childTable}/:${pk}", function () {
|
|
285
|
+
it("should partially update a child record", async function () {
|
|
286
|
+
const res = await request(app)
|
|
287
|
+
.patch(\`/${parentTable}/\${parentId}/${childTable}/1\`)
|
|
288
|
+
.send({});
|
|
289
|
+
assert.ok([200, 400, 404].includes(res.status));
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe("DELETE /${parentTable}/:${fkColumn}/${childTable}/:${pk}", function () {
|
|
294
|
+
it("should delete a child record", async function () {
|
|
295
|
+
const res = await request(app).delete(\`/${parentTable}/\${parentId}/${childTable}/1\`);
|
|
296
|
+
assert.ok([200, 204, 404].includes(res.status));
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
`;
|
|
301
|
+
}
|
|
302
|
+
|
|
111
303
|
/**
|
|
112
304
|
* Read model directory to discover table names from generated model files.
|
|
113
305
|
* Looks for .js files that are not index.js.
|
|
@@ -262,6 +454,51 @@ async function main() {
|
|
|
262
454
|
// OpenAPI generation is optional, don't fail
|
|
263
455
|
}
|
|
264
456
|
|
|
457
|
+
// Generate test files for all routes
|
|
458
|
+
const testsDir = path.resolve(path.dirname(routesDir), "tests");
|
|
459
|
+
if (!fs.existsSync(testsDir)) {
|
|
460
|
+
fs.mkdirSync(testsDir, { recursive: true });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
for (const table of tableNames) {
|
|
464
|
+
// Try to extract PK from model file
|
|
465
|
+
let pk = "id";
|
|
466
|
+
const modelPath = path.join(modelsDir, table + ".js");
|
|
467
|
+
if (fs.existsSync(modelPath)) {
|
|
468
|
+
const meta = parseModelFile(fs.readFileSync(modelPath, "utf8"), table);
|
|
469
|
+
if (meta && meta.primary_key) pk = meta.primary_key;
|
|
470
|
+
}
|
|
471
|
+
const testPath = path.join(testsDir, table + ".test.js");
|
|
472
|
+
fs.writeFileSync(testPath, generateTestFile(table, pk));
|
|
473
|
+
console.log(` Created ${testPath}`);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Generate child route test files
|
|
477
|
+
for (const rel of relationships) {
|
|
478
|
+
let pk = "id";
|
|
479
|
+
const modelPath = path.join(modelsDir, rel.child + ".js");
|
|
480
|
+
if (fs.existsSync(modelPath)) {
|
|
481
|
+
const meta = parseModelFile(
|
|
482
|
+
fs.readFileSync(modelPath, "utf8"),
|
|
483
|
+
rel.child,
|
|
484
|
+
);
|
|
485
|
+
if (meta && meta.primary_key) pk = meta.primary_key;
|
|
486
|
+
}
|
|
487
|
+
const testPath = path.join(
|
|
488
|
+
testsDir,
|
|
489
|
+
`${rel.child}_child_of_${rel.parent}.test.js`,
|
|
490
|
+
);
|
|
491
|
+
fs.writeFileSync(
|
|
492
|
+
testPath,
|
|
493
|
+
generateChildTestFile(rel.child, rel.parent, rel.fkColumn, pk),
|
|
494
|
+
);
|
|
495
|
+
console.log(` Created ${testPath}`);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
console.log(
|
|
499
|
+
`Generated ${tableNames.length + relationships.length} test file(s) in ${testsDir}`,
|
|
500
|
+
);
|
|
501
|
+
|
|
265
502
|
process.exit(0);
|
|
266
503
|
}
|
|
267
504
|
|
|
@@ -271,7 +508,9 @@ async function main() {
|
|
|
271
508
|
function parseModelFile(content, tableName) {
|
|
272
509
|
try {
|
|
273
510
|
// Extract structure JSON
|
|
274
|
-
const structMatch = content.match(
|
|
511
|
+
const structMatch = content.match(
|
|
512
|
+
/model\(\s*\n?\s*db,\s*\n?\s*"[^"]+",\s*\n?\s*(\{[\s\S]*?\}),/,
|
|
513
|
+
);
|
|
275
514
|
if (!structMatch) return null;
|
|
276
515
|
const structure = JSON.parse(structMatch[1]);
|
|
277
516
|
// Extract primary key
|
|
@@ -281,7 +520,7 @@ function parseModelFile(content, tableName) {
|
|
|
281
520
|
} catch (e) {
|
|
282
521
|
return null;
|
|
283
522
|
}
|
|
284
|
-
|
|
523
|
+
}
|
|
285
524
|
function parseArgs(argv) {
|
|
286
525
|
const args = {};
|
|
287
526
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -341,6 +580,8 @@ module.exports = {
|
|
|
341
580
|
generateRouteFile,
|
|
342
581
|
generateChildRouteFile,
|
|
343
582
|
generateRoutesIndexFile,
|
|
583
|
+
generateTestFile,
|
|
584
|
+
generateChildTestFile,
|
|
344
585
|
discoverModels,
|
|
345
586
|
safeVarName,
|
|
346
587
|
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Maps each supported database to its driver package(s).
|
|
5
|
+
*/
|
|
6
|
+
const DRIVER_MAP = {
|
|
7
|
+
mysql: ["mysql2"],
|
|
8
|
+
mariadb: ["mysql2"],
|
|
9
|
+
postgres: ["pg"],
|
|
10
|
+
sqlite3: ["better-sqlite3"],
|
|
11
|
+
mongodb: ["mongodb"],
|
|
12
|
+
mssql: ["mssql"],
|
|
13
|
+
cockroachdb: ["pg"],
|
|
14
|
+
oracle: ["oracledb"],
|
|
15
|
+
redis: ["ioredis"],
|
|
16
|
+
dynamodb: ["@aws-sdk/client-dynamodb", "@aws-sdk/lib-dynamodb"],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Collect dependencies and devDependencies based on user answers.
|
|
21
|
+
* @param {import('./types').InitAnswers} answers
|
|
22
|
+
* @returns {{ dependencies: Record<string, string>, devDependencies: Record<string, string> }}
|
|
23
|
+
*/
|
|
24
|
+
function collectDependencies(answers) {
|
|
25
|
+
const dependencies = {};
|
|
26
|
+
const devDependencies = {};
|
|
27
|
+
|
|
28
|
+
// Always included
|
|
29
|
+
dependencies["db-model-router"] = "latest";
|
|
30
|
+
dependencies["dotenv"] = "latest";
|
|
31
|
+
dependencies[answers.framework] = "latest";
|
|
32
|
+
dependencies["express-session"] = "latest";
|
|
33
|
+
|
|
34
|
+
// Database driver(s)
|
|
35
|
+
const drivers = DRIVER_MAP[answers.database] || [];
|
|
36
|
+
for (const driver of drivers) {
|
|
37
|
+
dependencies[driver] = "latest";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Session: redis
|
|
41
|
+
if (answers.session === "redis") {
|
|
42
|
+
dependencies["connect-redis"] = "latest";
|
|
43
|
+
// Only add ioredis if not already included via the database driver
|
|
44
|
+
if (answers.database !== "redis") {
|
|
45
|
+
dependencies["ioredis"] = "latest";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Optional middleware
|
|
50
|
+
if (answers.rateLimiting) {
|
|
51
|
+
dependencies["express-rate-limit"] = "latest";
|
|
52
|
+
}
|
|
53
|
+
if (answers.helmet) {
|
|
54
|
+
dependencies["helmet"] = "latest";
|
|
55
|
+
}
|
|
56
|
+
if (answers.logger) {
|
|
57
|
+
dependencies["winston"] = "latest";
|
|
58
|
+
if (answers.loki) {
|
|
59
|
+
dependencies["winston-loki"] = "latest";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Dev dependencies
|
|
64
|
+
devDependencies["nodemon"] = "latest";
|
|
65
|
+
|
|
66
|
+
return { dependencies, devDependencies };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns the package.json scripts.
|
|
71
|
+
* @param {string} [outputDir] - relative output directory for source files
|
|
72
|
+
* @returns {Record<string, string>}
|
|
73
|
+
*/
|
|
74
|
+
function getScripts(outputDir) {
|
|
75
|
+
const prefix = outputDir ? `${outputDir}/` : "";
|
|
76
|
+
return {
|
|
77
|
+
start: "node app.js",
|
|
78
|
+
dev: "nodemon app.js",
|
|
79
|
+
test: 'echo "Error: no test specified" && exit 1',
|
|
80
|
+
migrate: `node ${prefix}commons/migrate.js`,
|
|
81
|
+
add_migration: `node ${prefix}commons/add_migration.js`,
|
|
82
|
+
"docker:build": "docker build -t app .",
|
|
83
|
+
"docker:up": "docker compose up -d",
|
|
84
|
+
"docker:down": "docker compose down",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
DRIVER_MAP,
|
|
90
|
+
collectDependencies,
|
|
91
|
+
getScripts,
|
|
92
|
+
};
|