@deterministic-code/datasources-cli 0.1.13 → 0.1.15
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/commands.js +9 -4
- package/dist/detect.js +21 -7
- package/dist/env.js +7 -0
- package/dist/generate/CSharpRepositories.js +18 -14
- package/dist/generate/DeterministicProvider.js +25 -16
- package/dist/generate/RepositoryModel.js +10 -4
- package/dist/generate/RepositoryPlan.js +12 -5
- package/dist/generate/RustRepositories.js +42 -31
- package/dist/generate/TypeScriptRepositories.js +22 -18
- package/dist/generate/applyGenerate.js +11 -2
- package/dist/generate/applyMigrations.js +14 -17
- package/dist/generate/casing.js +28 -0
- package/dist/generate/destEnv.js +12 -0
- package/dist/generate/migrateUp.js +8 -41
- package/dist/generate/sqlDialects.js +29 -0
- package/dist/generate/sqlFlags.js +27 -0
- package/dist/migrateInit.js +4 -3
- package/dist/parse.js +102 -25
- package/dist/run.js +42 -67
- package/dist/setup.js +7 -9
- package/dist/version/applyVersion.js +11 -14
- package/dist/version/delta.js +0 -50
- package/dist/version/render.js +1 -11
- package/dist/wireRegister.js +29 -11
- package/dist/wireRustProviders.js +42 -0
- package/node_modules/@deterministic-code/csharp-generators/dist/import-generator.js +16 -12
- package/node_modules/@deterministic-code/csharp-generators/src/import-generator.test.ts +22 -11
- package/node_modules/@deterministic-code/csharp-generators/src/import-generator.ts +21 -13
- package/node_modules/@deterministic-code/datasources-code-generators/dist/nestedSelectTypes.js +2 -6
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.d.ts +2 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.js +37 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.d.ts +2 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.js +6 -0
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.d.ts +1 -1
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.js +3 -6
- package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/version-migrations.js +25 -14
- package/node_modules/@deterministic-code/datasources-code-generators/package.json +10 -8
- package/node_modules/@deterministic-code/deterministic-generators-common/README.md +61 -1
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/dist/specification-parser.js +128 -1
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/specification-parser.ts +1 -0
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/version-snapshot.ts +154 -0
- package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/yaml-node.ts +2 -2
- package/node_modules/@deterministic-code/deterministic-specifications-typescript/README.md +61 -1
- package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/specification-parser.ts +1 -0
- package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/version-snapshot.ts +154 -0
- package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/yaml-node.ts +2 -2
- package/node_modules/@deterministic-code/rust-generators/dist/import-generator.js +25 -15
- package/node_modules/@deterministic-code/rust-generators/src/import-generator.test.ts +11 -0
- package/node_modules/@deterministic-code/rust-generators/src/import-generator.ts +36 -18
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-types.js +6 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-validators.js +6 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-routes.js +1 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/generate-services.js +1 -1
- package/node_modules/@deterministic-code/typescript-generators/dist/import-generator.js +29 -21
- package/node_modules/@deterministic-code/typescript-generators/src/emit.ts +2 -5
- package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-types.ts +7 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-validators.ts +7 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-routes.ts +1 -1
- package/node_modules/@deterministic-code/typescript-generators/src/generate-services.ts +1 -1
- package/node_modules/@deterministic-code/typescript-generators/src/import-generator.test.ts +16 -0
- package/node_modules/@deterministic-code/typescript-generators/src/import-generator.ts +37 -22
- package/package.json +8 -8
|
@@ -1,33 +1,30 @@
|
|
|
1
1
|
import { isAbsolute, join } from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { generateSql } from "@deterministic-code/datasources-code-generators";
|
|
3
3
|
import { memoryReader } from "@deterministic-code/generators-common/deterministic-reader";
|
|
4
|
+
import { destEnv } from "./destEnv.js";
|
|
4
5
|
import { loadSpec } from "./loadSpec.js";
|
|
5
6
|
import { providerByName } from "./providers.js";
|
|
7
|
+
import { overlaySqlFlags } from "./sqlFlags.js";
|
|
8
|
+
import { sqlDialectsFromEnv } from "./sqlDialects.js";
|
|
6
9
|
import { withStoredProcedures } from "./storedProcedures.js";
|
|
7
10
|
import { writeEntries } from "./writeEntries.js";
|
|
8
11
|
const at = (root, path) => isAbsolute(path) ? path : join(root, path);
|
|
9
|
-
const afterMigrations = (filename) => filename.replace(/^[^/]+\/migrations\//, "");
|
|
10
12
|
const applyMigrations = async (command, flags, deps) => {
|
|
11
13
|
providerByName(command.provider);
|
|
12
14
|
const loaded = await loadSpec(deps.fs, at(flags.cwd, command.input));
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
reader: memoryReader(loaded.files),
|
|
22
|
-
settings: withStoredProcedures(loaded.settings, command.storedProcedures)
|
|
23
|
-
});
|
|
24
|
-
const remapped = command.migrationsPath === void 0 ? entries : entries.map((entry) => ({ ...entry, filename: afterMigrations(entry.filename) }));
|
|
25
|
-
const root = at(flags.cwd, command.migrationsPath ?? command.migrationsRoot);
|
|
15
|
+
const entries = await generateSql(
|
|
16
|
+
{
|
|
17
|
+
reader: memoryReader(loaded.files),
|
|
18
|
+
settings: overlaySqlFlags(withStoredProcedures(loaded.settings, command.storedProcedures), command)
|
|
19
|
+
},
|
|
20
|
+
sqlDialectsFromEnv(await destEnv(deps.fs, flags.cwd))
|
|
21
|
+
);
|
|
22
|
+
const root = at(flags.cwd, command.migrationsRoot);
|
|
26
23
|
if (flags.dryRun) {
|
|
27
|
-
for (const entry of
|
|
24
|
+
for (const entry of entries) deps.log(join(root, entry.filename));
|
|
28
25
|
return;
|
|
29
26
|
}
|
|
30
|
-
for (const path of await writeEntries(deps.fs, root,
|
|
27
|
+
for (const path of await writeEntries(deps.fs, root, entries)) deps.log(path);
|
|
31
28
|
};
|
|
32
29
|
export {
|
|
33
30
|
applyMigrations
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const caseFormats = ["Pascal", "Camel", "Snake", "Kebab", "Auto"];
|
|
2
|
+
const LITERAL_SEGMENTS = /* @__PURE__ */ new Set(["csharp", "typescript", "rust", "sql", "custom", "__tests__", "frontend"]);
|
|
3
|
+
const parseCaseFlag = (raw, name) => {
|
|
4
|
+
const parsed = caseFormats.find((format) => format.toLowerCase() === raw.toLowerCase());
|
|
5
|
+
if (parsed === void 0) throw new Error(`${name} must be one of [${caseFormats.join(", ")}] (got "${raw}").`);
|
|
6
|
+
return parsed;
|
|
7
|
+
};
|
|
8
|
+
const overlayCasingFlags = (settings, dialect, flags) => {
|
|
9
|
+
const prefix = `languages.${dialect}.casing`;
|
|
10
|
+
return {
|
|
11
|
+
...settings,
|
|
12
|
+
...flags.fileNames === void 0 ? {} : { [`${prefix}.file_names`]: flags.fileNames },
|
|
13
|
+
...flags.types === void 0 ? {} : { [`${prefix}.types`]: flags.types },
|
|
14
|
+
...flags.fields === void 0 ? {} : { [`${prefix}.fields`]: flags.fields },
|
|
15
|
+
...flags.directories === void 0 ? {} : { [`${prefix}.directories`]: flags.directories }
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const caseDirectories = (path, casing) => path.split("/").map((segment) => LITERAL_SEGMENTS.has(segment) || segment.includes(".") ? segment : casing.convertDirectories(segment)).join("/");
|
|
19
|
+
const typesPrefix = (dialect, casing, kind) => dialect === "typescript" ? ["typescript", casing.convertDirectories("types"), casing.convertDirectories("generated"), casing.convertDirectories(kind)].join("/") : dialect;
|
|
20
|
+
const repositoriesPrefix = (dialect, casing) => `${dialect}/${casing.convertDirectories("repositories")}`;
|
|
21
|
+
export {
|
|
22
|
+
caseDirectories,
|
|
23
|
+
caseFormats,
|
|
24
|
+
overlayCasingFlags,
|
|
25
|
+
parseCaseFlag,
|
|
26
|
+
repositoriesPrefix,
|
|
27
|
+
typesPrefix
|
|
28
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { overlayEnv, parseEnv } from "../env.js";
|
|
3
|
+
const destEnv = async (fs, cwd) => {
|
|
4
|
+
try {
|
|
5
|
+
return overlayEnv(parseEnv(await fs.readFile(join(cwd, ".env"))), process.env);
|
|
6
|
+
} catch {
|
|
7
|
+
return overlayEnv({}, process.env);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export {
|
|
11
|
+
destEnv
|
|
12
|
+
};
|
|
@@ -1,30 +1,8 @@
|
|
|
1
1
|
import { isAbsolute, join } from "node:path";
|
|
2
|
-
import { parseEnv, scheme } from "../env.js";
|
|
3
|
-
import { migrateProviders } from "../migrateInit.js";
|
|
2
|
+
import { overlayEnv, parseEnv, scheme } from "../env.js";
|
|
4
3
|
import { loadSpec } from "./loadSpec.js";
|
|
4
|
+
import { canonical, isSql, sqlDialectsFromEnv } from "./sqlDialects.js";
|
|
5
5
|
const at = (root, path) => isAbsolute(path) ? path : join(root, path);
|
|
6
|
-
const aliases = {
|
|
7
|
-
sqlite3: "sqlite",
|
|
8
|
-
postgresql: "postgres",
|
|
9
|
-
pg: "postgres",
|
|
10
|
-
mariadb: "mysql",
|
|
11
|
-
mssql: "sqlserver",
|
|
12
|
-
mssqlserver: "sqlserver",
|
|
13
|
-
ora: "oracle"
|
|
14
|
-
};
|
|
15
|
-
const canonical = (name) => {
|
|
16
|
-
const key = name.trim().toLowerCase();
|
|
17
|
-
return aliases[key] ?? key;
|
|
18
|
-
};
|
|
19
|
-
const isSql = (name) => migrateProviders.includes(name);
|
|
20
|
-
const sqlDialects = (settings) => {
|
|
21
|
-
const out = [];
|
|
22
|
-
for (const name of settings["backend.datasources"].split(",")) {
|
|
23
|
-
const key = canonical(name);
|
|
24
|
-
if (key !== "" && isSql(key) && !out.includes(key)) out.push(key);
|
|
25
|
-
}
|
|
26
|
-
return out;
|
|
27
|
-
};
|
|
28
6
|
const readEnv = async (fs, cwd) => {
|
|
29
7
|
try {
|
|
30
8
|
return parseEnv(await fs.readFile(join(cwd, ".env")));
|
|
@@ -32,20 +10,15 @@ const readEnv = async (fs, cwd) => {
|
|
|
32
10
|
return {};
|
|
33
11
|
}
|
|
34
12
|
};
|
|
35
|
-
const merged = (file, env) => ({
|
|
36
|
-
...file,
|
|
37
|
-
...env.PROVIDER ? { PROVIDER: env.PROVIDER } : {},
|
|
38
|
-
...env.DATASOURCE_URL ? { DATASOURCE_URL: env.DATASOURCE_URL } : {}
|
|
39
|
-
});
|
|
40
13
|
const inMemory = (url) => url === ":memory:" || url.includes(":memory:");
|
|
41
14
|
const applyMigrateUp = async (command, flags, deps, env = process.env) => {
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
const
|
|
15
|
+
await loadSpec(deps.fs, at(flags.cwd, command.input));
|
|
16
|
+
const values = overlayEnv(await readEnv(deps.fs, flags.cwd), env);
|
|
17
|
+
const dialects = sqlDialectsFromEnv(values);
|
|
45
18
|
const connection = values.DATASOURCE_URL ?? "";
|
|
46
19
|
const provider = canonical(values.PROVIDER || scheme(connection) || "");
|
|
47
20
|
if (!provider || !connection) {
|
|
48
|
-
deps.log("migrate-up skipped: set PROVIDER and DATASOURCE_URL, or pass --no-migrate");
|
|
21
|
+
deps.log("migrate-up skipped: set PROVIDER and DATASOURCE_URL, or pass --no-auto-migrate-up");
|
|
49
22
|
return;
|
|
50
23
|
}
|
|
51
24
|
if (inMemory(connection)) {
|
|
@@ -58,12 +31,9 @@ const applyMigrateUp = async (command, flags, deps, env = process.env) => {
|
|
|
58
31
|
}
|
|
59
32
|
if (!dialects.includes(provider))
|
|
60
33
|
throw new Error(
|
|
61
|
-
`migrate-up: provider ${provider} is not in
|
|
34
|
+
`migrate-up: provider ${provider} is not in INSTALLED_PROVIDERS (${dialects.join(", ") || "none"})`
|
|
62
35
|
);
|
|
63
36
|
const npx = (verb, extra = []) => [
|
|
64
|
-
"--yes",
|
|
65
|
-
"--package",
|
|
66
|
-
"@deterministic-code/migraters",
|
|
67
37
|
verb,
|
|
68
38
|
"--provider",
|
|
69
39
|
provider,
|
|
@@ -72,10 +42,7 @@ const applyMigrateUp = async (command, flags, deps, env = process.env) => {
|
|
|
72
42
|
...extra
|
|
73
43
|
];
|
|
74
44
|
const setup = npx("migrate-setup");
|
|
75
|
-
const up = npx(
|
|
76
|
-
"migrate-up",
|
|
77
|
-
command.migrationsPath ? ["--migrations-path", command.migrationsPath] : ["--migrations-root", command.migrationsRoot]
|
|
78
|
-
);
|
|
45
|
+
const up = npx("migrate-up", ["--migrations-root", command.migrationsRoot]);
|
|
79
46
|
deps.log(`$ npx ${setup.join(" ")}`);
|
|
80
47
|
if (!flags.dryRun) await deps.run("npx", setup, flags.cwd);
|
|
81
48
|
deps.log(`$ npx ${up.join(" ")}`);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { scheme, splitProviders } from "../env.js";
|
|
2
|
+
import { migrateProviders } from "../migrateInit.js";
|
|
3
|
+
const aliases = {
|
|
4
|
+
sqlite3: "sqlite",
|
|
5
|
+
postgresql: "postgres",
|
|
6
|
+
pg: "postgres",
|
|
7
|
+
mariadb: "mysql",
|
|
8
|
+
mssql: "sqlserver",
|
|
9
|
+
mssqlserver: "sqlserver",
|
|
10
|
+
ora: "oracle"
|
|
11
|
+
};
|
|
12
|
+
const canonical = (name) => {
|
|
13
|
+
const key = name.trim().toLowerCase();
|
|
14
|
+
return aliases[key] ?? key;
|
|
15
|
+
};
|
|
16
|
+
const isSql = (name) => migrateProviders.includes(name);
|
|
17
|
+
const sqlDialectsFromEnv = (env) => {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const name of splitProviders(env.INSTALLED_PROVIDERS || env.PROVIDER || scheme(env.DATASOURCE_URL || "") || "")) {
|
|
20
|
+
const key = canonical(name);
|
|
21
|
+
if (key !== "" && isSql(key) && !out.includes(key)) out.push(key);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
};
|
|
25
|
+
export {
|
|
26
|
+
canonical,
|
|
27
|
+
isSql,
|
|
28
|
+
sqlDialectsFromEnv
|
|
29
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const letterCases = ["Upper", "Lower", "Auto"];
|
|
2
|
+
const parseLetterCaseFlag = (raw, name) => {
|
|
3
|
+
const parsed = letterCases.find((format) => format.toLowerCase() === raw.toLowerCase());
|
|
4
|
+
if (parsed === void 0) throw new Error(`${name} must be one of [${letterCases.join(", ")}] (got "${raw}").`);
|
|
5
|
+
return parsed;
|
|
6
|
+
};
|
|
7
|
+
const overlaySqlFlags = (settings, flags) => ({
|
|
8
|
+
...settings,
|
|
9
|
+
...flags.pluralizeTableNames === void 0 ? {} : { "datasource.pluralize_datatable_names": flags.pluralizeTableNames ? "true" : "false" },
|
|
10
|
+
...flags.tableNames === void 0 ? {} : { "datasource.casing.types": flags.tableNames },
|
|
11
|
+
...flags.columnNames === void 0 ? {} : { "datasource.casing.fields": flags.columnNames },
|
|
12
|
+
...flags.objectNames === void 0 ? {} : { "datasource.casing.objects": flags.objectNames },
|
|
13
|
+
...flags.sqlKeywords === void 0 ? {} : { "datasource.casing.keywords": flags.sqlKeywords }
|
|
14
|
+
});
|
|
15
|
+
const sqlFlagsOf = (flags) => ({
|
|
16
|
+
pluralizeTableNames: flags.pluralizeTableNames,
|
|
17
|
+
tableNames: flags.tableNames,
|
|
18
|
+
columnNames: flags.columnNames,
|
|
19
|
+
objectNames: flags.objectNames,
|
|
20
|
+
sqlKeywords: flags.sqlKeywords
|
|
21
|
+
});
|
|
22
|
+
export {
|
|
23
|
+
letterCases,
|
|
24
|
+
overlaySqlFlags,
|
|
25
|
+
parseLetterCaseFlag,
|
|
26
|
+
sqlFlagsOf
|
|
27
|
+
};
|
package/dist/migrateInit.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
const migrateProviders = ["sqlite", "postgres", "mysql", "sqlserver", "oracle"];
|
|
2
2
|
const migrateLanguage = (ecosystem) => ecosystem === "ts" ? "typescript" : ecosystem;
|
|
3
3
|
const sqlMigrateProviders = (names) => migrateProviders.filter((name) => names.includes(name));
|
|
4
|
-
const
|
|
5
|
-
|
|
4
|
+
const migratersPackage = (env = process.env) => env.MIGRATERS_PACKAGE || "@deterministic-code/migraters";
|
|
5
|
+
const migrateInitCommands = (dialects, language, env = process.env) => dialects.length === 0 ? [] : [
|
|
6
|
+
{ command: "npm", args: ["install", migratersPackage(env)] },
|
|
6
7
|
{
|
|
7
8
|
command: "npx",
|
|
8
9
|
args: [
|
|
9
10
|
"--yes",
|
|
10
11
|
"--package",
|
|
11
|
-
|
|
12
|
+
migratersPackage(env),
|
|
12
13
|
"migrate-init",
|
|
13
14
|
"--language",
|
|
14
15
|
language,
|
package/dist/parse.js
CHANGED
|
@@ -1,42 +1,62 @@
|
|
|
1
1
|
import { isEcosystem } from "./detect.js";
|
|
2
|
+
import { parseCaseFlag } from "./generate/casing.js";
|
|
3
|
+
import { parseLetterCaseFlag } from "./generate/sqlFlags.js";
|
|
2
4
|
import { isDialect } from "./generate/GenerateRequest.js";
|
|
3
5
|
const generateTargets = ["all", "types", "repositories", "datasource"];
|
|
4
6
|
const help = `Usage: datasources <command> [options]
|
|
5
7
|
|
|
6
|
-
setup [
|
|
8
|
+
setup [name...] Interactive .env, datasource install, and optional deterministic/
|
|
7
9
|
--cwd <dir> Consumer project directory (default: .)
|
|
8
|
-
--
|
|
10
|
+
--languages ts|rust|csharp Project languages (default: every type found)
|
|
11
|
+
--datasources <name...> Datasources to install (default: existing .env)
|
|
9
12
|
--dry-run Print package-manager commands without running them
|
|
10
13
|
--yes Setup without prompts (defaults / existing .env)
|
|
11
14
|
|
|
12
|
-
add
|
|
15
|
+
add [name...] Add datasource packages
|
|
13
16
|
--cwd <dir> Consumer project directory (default: .)
|
|
14
|
-
--
|
|
17
|
+
--languages ts|rust|csharp Project languages (default: every type found)
|
|
18
|
+
--datasources <name...> Datasources to add
|
|
15
19
|
--dry-run Print package-manager commands without running them
|
|
16
20
|
|
|
17
|
-
remove
|
|
21
|
+
remove [name...] Remove datasource packages
|
|
18
22
|
--cwd <dir> Consumer project directory (default: .)
|
|
19
|
-
--
|
|
23
|
+
--languages ts|rust|csharp Project languages (default: every type found)
|
|
24
|
+
--datasources <name...> Datasources to remove
|
|
20
25
|
--dry-run Print package-manager commands without running them
|
|
21
26
|
|
|
22
27
|
generate <all|types|repositories|datasource>
|
|
23
28
|
Types, repository classes, and SQL
|
|
29
|
+
https://deterministic-code.github.io/datasources/cli.html#generate
|
|
24
30
|
--dialect csharp|typescript|rust
|
|
25
31
|
--provider <name> Spec provider (default: deterministic)
|
|
26
32
|
--input <dir> Deterministic project (default: ./deterministic)
|
|
27
33
|
--output <dir> Generated files (default: ./generated)
|
|
28
34
|
--no-migrations Skip SQL migrations (generate all writes them)
|
|
29
|
-
--no-migrate
|
|
35
|
+
--no-auto-migrate-up Skip migrate-up (generate all applies them)
|
|
30
36
|
--migrations-root <dir> Root prefix for generate all (default: sql)
|
|
31
|
-
--migrations-path <dir> One migrations directory (single SQL dialect)
|
|
32
37
|
--stored-procedures Emit stored-procedure migrations when the dialect can
|
|
38
|
+
--pluralize-table-names Plural table names in SQL and runtime queries (default)
|
|
39
|
+
--no-pluralize-table-names Singular table names (procedure names stay plural)
|
|
40
|
+
--table-names Pascal|Camel|Snake|Kebab|Auto
|
|
41
|
+
--column-names Pascal|Camel|Snake|Kebab|Auto
|
|
42
|
+
--object-names Upper|Lower|Auto
|
|
43
|
+
--sql-keywords Upper|Lower|Auto
|
|
44
|
+
--file-names Pascal|Camel|Snake|Kebab|Auto
|
|
45
|
+
--type-names|--types Pascal|Camel|Snake|Kebab|Auto
|
|
46
|
+
--field-names|--fields Pascal|Camel|Snake|Kebab|Auto
|
|
47
|
+
--folder-names|--directories Pascal|Camel|Snake|Kebab|Auto
|
|
33
48
|
|
|
34
49
|
migrations create SQL migrations from the spec (migraters layout)
|
|
35
50
|
--provider <name> Spec provider (default: deterministic)
|
|
36
51
|
--input <dir> Deterministic project (default: ./deterministic)
|
|
37
52
|
--migrations-root <dir> Root prefix (default: sql)
|
|
38
|
-
--migrations-path <dir> One migrations directory (single SQL dialect)
|
|
39
53
|
--stored-procedures Emit stored-procedure migrations when the dialect can
|
|
54
|
+
--pluralize-table-names Plural table names in SQL (default)
|
|
55
|
+
--no-pluralize-table-names Singular table names (procedure names stay plural)
|
|
56
|
+
--table-names Pascal|Camel|Snake|Kebab|Auto
|
|
57
|
+
--column-names Pascal|Camel|Snake|Kebab|Auto
|
|
58
|
+
--object-names Upper|Lower|Auto
|
|
59
|
+
--sql-keywords Upper|Lower|Auto
|
|
40
60
|
|
|
41
61
|
version Snapshot top-level YAML as the next version-*/diff.yaml
|
|
42
62
|
--cwd <dir> Consumer project directory (default: .)
|
|
@@ -48,7 +68,7 @@ const take = (argv, index, name) => argv[index] ?? (() => {
|
|
|
48
68
|
throw new Error(`Missing value for ${name}`);
|
|
49
69
|
})();
|
|
50
70
|
const parseArgs = (argv, cwd = ".") => {
|
|
51
|
-
const flags = { cwd, dryRun: false, yes: false };
|
|
71
|
+
const flags = { cwd, languages: [], datasources: [], dryRun: false, yes: false };
|
|
52
72
|
const generate = {
|
|
53
73
|
dialect: "",
|
|
54
74
|
provider: "deterministic",
|
|
@@ -58,15 +78,29 @@ const parseArgs = (argv, cwd = ".") => {
|
|
|
58
78
|
migrate: true,
|
|
59
79
|
storedProcedures: false,
|
|
60
80
|
migrationsRoot: "sql",
|
|
61
|
-
|
|
81
|
+
fileNames: void 0,
|
|
82
|
+
types: void 0,
|
|
83
|
+
fields: void 0,
|
|
84
|
+
directories: void 0,
|
|
85
|
+
pluralizeTableNames: void 0,
|
|
86
|
+
tableNames: void 0,
|
|
87
|
+
columnNames: void 0,
|
|
88
|
+
objectNames: void 0,
|
|
89
|
+
sqlKeywords: void 0
|
|
62
90
|
};
|
|
63
91
|
const rest = [];
|
|
64
92
|
for (let i = 0; i < argv.length; i++) {
|
|
65
93
|
const arg = argv[i];
|
|
66
94
|
if (arg === "--cwd") flags.cwd = argv[++i] ?? flags.cwd;
|
|
67
95
|
else if (arg.startsWith("--cwd=")) flags.cwd = arg.slice("--cwd=".length);
|
|
68
|
-
else if (arg === "--
|
|
69
|
-
|
|
96
|
+
else if (arg === "--languages") {
|
|
97
|
+
i = takeList(argv, ++i, "--languages", (value) => flags.languages.push(language(value)));
|
|
98
|
+
} else if (arg.startsWith("--languages="))
|
|
99
|
+
splitList(arg.slice("--languages=".length), "--languages").forEach((value) => flags.languages.push(language(value)));
|
|
100
|
+
else if (arg === "--datasources") {
|
|
101
|
+
i = takeList(argv, ++i, "--datasources", (value) => flags.datasources.push(value));
|
|
102
|
+
} else if (arg.startsWith("--datasources="))
|
|
103
|
+
flags.datasources.push(...splitList(arg.slice("--datasources=".length), "--datasources"));
|
|
70
104
|
else if (arg === "--dry-run") flags.dryRun = true;
|
|
71
105
|
else if (arg === "--yes" || arg === "-y") flags.yes = true;
|
|
72
106
|
else if (arg === "--dialect") generate.dialect = take(argv, ++i, "--dialect");
|
|
@@ -78,23 +112,41 @@ const parseArgs = (argv, cwd = ".") => {
|
|
|
78
112
|
else if (arg === "--output") generate.output = take(argv, ++i, "--output");
|
|
79
113
|
else if (arg.startsWith("--output=")) generate.output = arg.slice("--output=".length);
|
|
80
114
|
else if (arg === "--no-migrations") generate.migrations = false;
|
|
81
|
-
else if (arg === "--no-migrate") generate.migrate = false;
|
|
115
|
+
else if (arg === "--no-auto-migrate-up") generate.migrate = false;
|
|
82
116
|
else if (arg === "--stored-procedures") generate.storedProcedures = true;
|
|
117
|
+
else if (arg === "--pluralize-table-names") generate.pluralizeTableNames = true;
|
|
118
|
+
else if (arg === "--no-pluralize-table-names") generate.pluralizeTableNames = false;
|
|
119
|
+
else if (arg === "--table-names") generate.tableNames = parseCaseFlag(take(argv, ++i, arg), arg);
|
|
120
|
+
else if (arg.startsWith("--table-names=")) generate.tableNames = parseCaseFlag(arg.slice("--table-names=".length), "--table-names");
|
|
121
|
+
else if (arg === "--column-names") generate.columnNames = parseCaseFlag(take(argv, ++i, arg), arg);
|
|
122
|
+
else if (arg.startsWith("--column-names=")) generate.columnNames = parseCaseFlag(arg.slice("--column-names=".length), "--column-names");
|
|
123
|
+
else if (arg === "--object-names") generate.objectNames = parseLetterCaseFlag(take(argv, ++i, arg), arg);
|
|
124
|
+
else if (arg.startsWith("--object-names=")) generate.objectNames = parseLetterCaseFlag(arg.slice("--object-names=".length), "--object-names");
|
|
125
|
+
else if (arg === "--sql-keywords") generate.sqlKeywords = parseLetterCaseFlag(take(argv, ++i, arg), arg);
|
|
126
|
+
else if (arg.startsWith("--sql-keywords=")) generate.sqlKeywords = parseLetterCaseFlag(arg.slice("--sql-keywords=".length), "--sql-keywords");
|
|
83
127
|
else if (arg === "--migrations-root") generate.migrationsRoot = take(argv, ++i, "--migrations-root");
|
|
84
128
|
else if (arg.startsWith("--migrations-root=")) generate.migrationsRoot = arg.slice("--migrations-root=".length);
|
|
85
|
-
else if (arg === "--
|
|
86
|
-
|
|
129
|
+
else if (arg === "--file-names" || arg === "--type-names" || arg === "--types" || arg === "--field-names" || arg === "--fields" || arg === "--folder-names" || arg === "--directories") {
|
|
130
|
+
const key = arg === "--file-names" ? "fileNames" : arg === "--type-names" || arg === "--types" ? "types" : arg === "--field-names" || arg === "--fields" ? "fields" : "directories";
|
|
131
|
+
generate[key] = parseCaseFlag(take(argv, ++i, arg), arg);
|
|
132
|
+
} else if (arg.startsWith("--file-names=")) generate.fileNames = parseCaseFlag(arg.slice("--file-names=".length), "--file-names");
|
|
133
|
+
else if (arg.startsWith("--type-names=")) generate.types = parseCaseFlag(arg.slice("--type-names=".length), "--type-names");
|
|
134
|
+
else if (arg.startsWith("--types=")) generate.types = parseCaseFlag(arg.slice("--types=".length), "--types");
|
|
135
|
+
else if (arg.startsWith("--field-names=")) generate.fields = parseCaseFlag(arg.slice("--field-names=".length), "--field-names");
|
|
136
|
+
else if (arg.startsWith("--fields=")) generate.fields = parseCaseFlag(arg.slice("--fields=".length), "--fields");
|
|
137
|
+
else if (arg.startsWith("--folder-names=")) generate.directories = parseCaseFlag(arg.slice("--folder-names=".length), "--folder-names");
|
|
138
|
+
else if (arg.startsWith("--directories=")) generate.directories = parseCaseFlag(arg.slice("--directories=".length), "--directories");
|
|
87
139
|
else if (arg === "--help" || arg === "-h") return { command: { kind: "help" }, flags };
|
|
88
140
|
else rest.push(arg);
|
|
89
141
|
}
|
|
90
142
|
const [verb, ...names] = rest;
|
|
91
|
-
return { command: commandOf(verb, names, generate), flags };
|
|
143
|
+
return { command: commandOf(verb, names, flags.datasources, generate), flags };
|
|
92
144
|
};
|
|
93
|
-
const commandOf = (verb, names, generate) => {
|
|
145
|
+
const commandOf = (verb, names, datasources, generate) => {
|
|
94
146
|
if (verb === void 0 || verb === "help") return { kind: "help" };
|
|
95
|
-
if (verb === "setup") return { kind: "setup", providers: names };
|
|
96
|
-
if (verb === "add") return { kind: "add", providers: names };
|
|
97
|
-
if (verb === "remove") return { kind: "remove", providers: names };
|
|
147
|
+
if (verb === "setup") return { kind: "setup", providers: unique([...datasources, ...names]) };
|
|
148
|
+
if (verb === "add") return { kind: "add", providers: unique([...datasources, ...names]) };
|
|
149
|
+
if (verb === "remove") return { kind: "remove", providers: unique([...datasources, ...names]) };
|
|
98
150
|
if (verb === "generate") return generateCommand(names, generate);
|
|
99
151
|
if (verb === "migrations") return migrationsCommand(names, generate);
|
|
100
152
|
if (verb === "version") return versionCommand(names, generate.input);
|
|
@@ -111,7 +163,11 @@ ${help}`);
|
|
|
111
163
|
input: generate.input,
|
|
112
164
|
storedProcedures: generate.storedProcedures,
|
|
113
165
|
migrationsRoot: generate.migrationsRoot,
|
|
114
|
-
|
|
166
|
+
pluralizeTableNames: generate.pluralizeTableNames,
|
|
167
|
+
tableNames: generate.tableNames,
|
|
168
|
+
columnNames: generate.columnNames,
|
|
169
|
+
objectNames: generate.objectNames,
|
|
170
|
+
sqlKeywords: generate.sqlKeywords
|
|
115
171
|
};
|
|
116
172
|
};
|
|
117
173
|
const versionCommand = (names, input) => {
|
|
@@ -137,12 +193,33 @@ ${help}`);
|
|
|
137
193
|
migrate: generate.migrate,
|
|
138
194
|
storedProcedures: generate.storedProcedures,
|
|
139
195
|
migrationsRoot: generate.migrationsRoot,
|
|
140
|
-
|
|
196
|
+
fileNames: generate.fileNames,
|
|
197
|
+
types: generate.types,
|
|
198
|
+
fields: generate.fields,
|
|
199
|
+
directories: generate.directories,
|
|
200
|
+
pluralizeTableNames: generate.pluralizeTableNames,
|
|
201
|
+
tableNames: generate.tableNames,
|
|
202
|
+
columnNames: generate.columnNames,
|
|
203
|
+
objectNames: generate.objectNames,
|
|
204
|
+
sqlKeywords: generate.sqlKeywords
|
|
141
205
|
};
|
|
142
206
|
};
|
|
143
|
-
const
|
|
144
|
-
throw new Error(`Unknown --
|
|
207
|
+
const language = (value) => value === "typescript" ? "ts" : isEcosystem(value) ? value : (() => {
|
|
208
|
+
throw new Error(`Unknown --languages ${value}. Use ts|rust|csharp`);
|
|
145
209
|
})();
|
|
210
|
+
const unique = (names) => [...new Set(names)];
|
|
211
|
+
const splitList = (value, name) => {
|
|
212
|
+
const names = value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
213
|
+
return names.length ? names : (() => {
|
|
214
|
+
throw new Error(`Missing value for ${name}`);
|
|
215
|
+
})();
|
|
216
|
+
};
|
|
217
|
+
const takeList = (argv, index, name, push) => {
|
|
218
|
+
if (index >= argv.length || argv[index].startsWith("-")) throw new Error(`Missing value for ${name}`);
|
|
219
|
+
let i = index;
|
|
220
|
+
while (i < argv.length && !argv[i].startsWith("-")) push(argv[i++]);
|
|
221
|
+
return i - 1;
|
|
222
|
+
};
|
|
146
223
|
export {
|
|
147
224
|
generateTargets,
|
|
148
225
|
help,
|
package/dist/run.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { access, copyFile, mkdir } from "node:fs/promises";
|
|
2
1
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
2
|
+
import { requireProviders } from "./catalog.js";
|
|
4
3
|
import { addCommands, removeCommands } from "./commands.js";
|
|
5
|
-
import { csharpTarget, detect,
|
|
4
|
+
import { csharpTarget, detect, requireProjects, resolveLanguages } from "./detect.js";
|
|
6
5
|
import { parseEnv, serializeEnv, updateEnvProviders } from "./env.js";
|
|
7
6
|
import { defaultDatasourceYaml } from "./generate/loadSpec.js";
|
|
8
7
|
import {
|
|
@@ -15,9 +14,11 @@ import { applyMigrations } from "./generate/applyMigrations.js";
|
|
|
15
14
|
import { applyMigrateUp } from "./generate/migrateUp.js";
|
|
16
15
|
import { migrateInitCommands, migrateLanguage, sqlMigrateProviders } from "./migrateInit.js";
|
|
17
16
|
import { help, parseArgs } from "./parse.js";
|
|
17
|
+
import { sqlFlagsOf } from "./generate/sqlFlags.js";
|
|
18
18
|
import { applyVersion } from "./version/applyVersion.js";
|
|
19
19
|
import { answersForSetup, envFromAnswers, promptSetup, starterTypesYaml } from "./setup.js";
|
|
20
20
|
import { wireRegister } from "./wireRegister.js";
|
|
21
|
+
import { wireRustProviders } from "./wireRustProviders.js";
|
|
21
22
|
const run = async (argv, deps, cwd = ".") => {
|
|
22
23
|
try {
|
|
23
24
|
const parsed = parseArgs(argv, cwd);
|
|
@@ -45,7 +46,7 @@ const dispatch = async (command, flags, deps) => {
|
|
|
45
46
|
input: command.input,
|
|
46
47
|
storedProcedures: command.storedProcedures,
|
|
47
48
|
migrationsRoot: command.migrationsRoot,
|
|
48
|
-
...command
|
|
49
|
+
...sqlFlagsOf(command)
|
|
49
50
|
},
|
|
50
51
|
flags,
|
|
51
52
|
deps
|
|
@@ -53,33 +54,41 @@ const dispatch = async (command, flags, deps) => {
|
|
|
53
54
|
if (command.migrate) await applyMigrateUp(command, flags, deps);
|
|
54
55
|
};
|
|
55
56
|
const needNames = (names, verb) => names.length ? names : (() => {
|
|
56
|
-
throw new Error(`Usage: datasources ${verb} <
|
|
57
|
+
throw new Error(`Usage: datasources ${verb} --datasources <name...>`);
|
|
57
58
|
})();
|
|
58
59
|
const applySetup = async (flags, deps, requested) => {
|
|
59
60
|
const entries = await deps.fs.readdir(flags.cwd);
|
|
60
61
|
const found = detect(entries);
|
|
61
|
-
const existing =
|
|
62
|
+
const existing = {
|
|
63
|
+
...await readEnv(deps.fs, flags.cwd),
|
|
64
|
+
...process.env.INSTALLED_PROVIDERS ? { INSTALLED_PROVIDERS: process.env.INSTALLED_PROVIDERS } : {},
|
|
65
|
+
...process.env.PROVIDER ? { PROVIDER: process.env.PROVIDER } : {},
|
|
66
|
+
...process.env.DATASOURCE_URL ? { DATASOURCE_URL: process.env.DATASOURCE_URL } : {}
|
|
67
|
+
};
|
|
62
68
|
const specDir = join(flags.cwd, "deterministic");
|
|
63
69
|
const typesPath = join(specDir, "types.yaml");
|
|
64
70
|
const datasourcePath = join(specDir, "datasource.yaml");
|
|
65
71
|
const missingSpec = await optional(deps.fs, typesPath) === void 0;
|
|
66
|
-
const answers = flags.yes ? { ...answersForSetup(existing, requested),
|
|
67
|
-
const
|
|
72
|
+
const answers = flags.yes ? { ...answersForSetup(existing, requested), languages: flags.languages, scaffold: false } : await promptSetup(deps.prompt, existing, found, flags.languages, missingSpec, requested);
|
|
73
|
+
const languages = resolveLanguages(found, answers.languages ?? flags.languages);
|
|
74
|
+
requireProjects(languages, entries);
|
|
68
75
|
const selected = requireProviders(answers.providers);
|
|
69
|
-
const installed = await readInstalled(deps.fs, flags.cwd, ecosystem, entries);
|
|
70
76
|
if (!flags.dryRun) await writeEnv(deps.fs, flags.cwd, { ...existing, ...envFromAnswers(answers) });
|
|
71
|
-
|
|
72
|
-
flags,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
for (const language of languages) {
|
|
78
|
+
const installed = await readInstalled(deps.fs, flags.cwd, language, entries);
|
|
79
|
+
await applyPackages(
|
|
80
|
+
flags,
|
|
81
|
+
deps,
|
|
82
|
+
language,
|
|
83
|
+
entries,
|
|
84
|
+
selected.filter((name) => !installed.includes(name)),
|
|
85
|
+
installed.filter((name) => !selected.includes(name)),
|
|
86
|
+
selected
|
|
87
|
+
);
|
|
88
|
+
await applyMigrateInit(flags, deps, language, selected);
|
|
89
|
+
const dialect = migrateLanguage(language);
|
|
90
|
+
await wireRegister(flags.cwd, "generated", dialect, flags.dryRun, deps);
|
|
91
|
+
}
|
|
83
92
|
if (!answers.scaffold) return;
|
|
84
93
|
if (flags.dryRun) {
|
|
85
94
|
deps.log(typesPath);
|
|
@@ -93,16 +102,19 @@ const applySetup = async (flags, deps, requested) => {
|
|
|
93
102
|
const applyAddRemove = async (flags, deps, add, remove) => {
|
|
94
103
|
const entries = await deps.fs.readdir(flags.cwd);
|
|
95
104
|
const found = detect(entries);
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
const remaining = [
|
|
99
|
-
...installed.filter((name) => !remove.includes(name)),
|
|
100
|
-
...add.filter((name) => !installed.includes(name))
|
|
101
|
-
];
|
|
105
|
+
const languages = resolveLanguages(found, flags.languages);
|
|
106
|
+
requireProjects(languages, entries);
|
|
102
107
|
const env = await readEnvFile(deps.fs, join(flags.cwd, ".env"));
|
|
103
108
|
if (env && !flags.dryRun) await writeEnv(deps.fs, flags.cwd, updateEnvProviders(env, add, remove));
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
for (const language of languages) {
|
|
110
|
+
const installed = await readInstalled(deps.fs, flags.cwd, language, entries);
|
|
111
|
+
const remaining = [
|
|
112
|
+
...installed.filter((name) => !remove.includes(name)),
|
|
113
|
+
...add.filter((name) => !installed.includes(name))
|
|
114
|
+
];
|
|
115
|
+
await applyPackages(flags, deps, language, entries, add, remove, remaining);
|
|
116
|
+
await applyMigrateInit(flags, deps, language, remaining);
|
|
117
|
+
}
|
|
106
118
|
};
|
|
107
119
|
const applyPackages = async (flags, deps, ecosystem, entries, add, remove, remaining) => {
|
|
108
120
|
const procs = [
|
|
@@ -113,17 +125,7 @@ const applyPackages = async (flags, deps, ecosystem, entries, add, remove, remai
|
|
|
113
125
|
deps.log(`$ ${proc.command} ${proc.args.join(" ")}`);
|
|
114
126
|
if (!flags.dryRun) await deps.run(proc.command, proc.args, flags.cwd);
|
|
115
127
|
}
|
|
116
|
-
if (ecosystem === "rust")
|
|
117
|
-
for (const name of add) {
|
|
118
|
-
const proc = { command: "cargo", args: ["build", "-p", catalog[name].cargo] };
|
|
119
|
-
deps.log(`$ ${proc.command} ${proc.args.join(" ")}`);
|
|
120
|
-
if (!flags.dryRun) {
|
|
121
|
-
await deps.run(proc.command, proc.args, flags.cwd);
|
|
122
|
-
const copied = await copyPlugin(flags.cwd, catalog[name].cargo);
|
|
123
|
-
if (copied) deps.log(`copy ${copied}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
128
|
+
if (ecosystem === "rust") await wireRustProviders(flags.cwd, remaining, flags.dryRun, deps);
|
|
127
129
|
};
|
|
128
130
|
const applyMigrateInit = async (flags, deps, ecosystem, remaining) => {
|
|
129
131
|
for (const proc of migrateInitCommands(sqlMigrateProviders(remaining), migrateLanguage(ecosystem))) {
|
|
@@ -161,33 +163,6 @@ const optional = async (fs, path) => {
|
|
|
161
163
|
return void 0;
|
|
162
164
|
}
|
|
163
165
|
};
|
|
164
|
-
const pluginFileName = (cargoName, platform = process.platform) => {
|
|
165
|
-
const stem = cargoName.replaceAll("-", "_");
|
|
166
|
-
return platform === "win32" ? `${stem}.dll` : platform === "darwin" ? `lib${stem}.dylib` : `lib${stem}.so`;
|
|
167
|
-
};
|
|
168
|
-
const copyPlugin = async (cwd, cargoName) => {
|
|
169
|
-
const file = pluginFileName(cargoName);
|
|
170
|
-
const source = await firstFile(
|
|
171
|
-
[0, 1, 2].map((up) => join(cwd, ...Array.from({ length: up }, () => ".."), "target", "debug", file))
|
|
172
|
-
);
|
|
173
|
-
if (!source) return void 0;
|
|
174
|
-
const dest = join(cwd, "plugins", file);
|
|
175
|
-
await mkdir(join(cwd, "plugins"), { recursive: true });
|
|
176
|
-
await copyFile(source, dest);
|
|
177
|
-
return dest;
|
|
178
|
-
};
|
|
179
|
-
const firstFile = async (paths) => {
|
|
180
|
-
for (const path of paths) {
|
|
181
|
-
try {
|
|
182
|
-
await access(path);
|
|
183
|
-
return path;
|
|
184
|
-
} catch {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return void 0;
|
|
189
|
-
};
|
|
190
166
|
export {
|
|
191
|
-
pluginFileName,
|
|
192
167
|
run
|
|
193
168
|
};
|