@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.
Files changed (62) hide show
  1. package/dist/commands.js +9 -4
  2. package/dist/detect.js +21 -7
  3. package/dist/env.js +7 -0
  4. package/dist/generate/CSharpRepositories.js +18 -14
  5. package/dist/generate/DeterministicProvider.js +25 -16
  6. package/dist/generate/RepositoryModel.js +10 -4
  7. package/dist/generate/RepositoryPlan.js +12 -5
  8. package/dist/generate/RustRepositories.js +42 -31
  9. package/dist/generate/TypeScriptRepositories.js +22 -18
  10. package/dist/generate/applyGenerate.js +11 -2
  11. package/dist/generate/applyMigrations.js +14 -17
  12. package/dist/generate/casing.js +28 -0
  13. package/dist/generate/destEnv.js +12 -0
  14. package/dist/generate/migrateUp.js +8 -41
  15. package/dist/generate/sqlDialects.js +29 -0
  16. package/dist/generate/sqlFlags.js +27 -0
  17. package/dist/migrateInit.js +4 -3
  18. package/dist/parse.js +102 -25
  19. package/dist/run.js +42 -67
  20. package/dist/setup.js +7 -9
  21. package/dist/version/applyVersion.js +11 -14
  22. package/dist/version/delta.js +0 -50
  23. package/dist/version/render.js +1 -11
  24. package/dist/wireRegister.js +29 -11
  25. package/dist/wireRustProviders.js +42 -0
  26. package/node_modules/@deterministic-code/csharp-generators/dist/import-generator.js +16 -12
  27. package/node_modules/@deterministic-code/csharp-generators/src/import-generator.test.ts +22 -11
  28. package/node_modules/@deterministic-code/csharp-generators/src/import-generator.ts +21 -13
  29. package/node_modules/@deterministic-code/datasources-code-generators/dist/nestedSelectTypes.js +2 -6
  30. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.d.ts +2 -0
  31. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/infer-reference-types.js +37 -0
  32. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.d.ts +2 -0
  33. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/reference-target.js +6 -0
  34. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.d.ts +1 -1
  35. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/sql-schema.js +3 -6
  36. package/node_modules/@deterministic-code/datasources-code-generators/dist/sql/common/version-migrations.js +25 -14
  37. package/node_modules/@deterministic-code/datasources-code-generators/package.json +10 -8
  38. package/node_modules/@deterministic-code/deterministic-generators-common/README.md +61 -1
  39. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/dist/specification-parser.js +128 -1
  40. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/specification-parser.ts +1 -0
  41. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/version-snapshot.ts +154 -0
  42. package/node_modules/@deterministic-code/deterministic-generators-common/typescript/parser/yaml-node.ts +2 -2
  43. package/node_modules/@deterministic-code/deterministic-specifications-typescript/README.md +61 -1
  44. package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/specification-parser.ts +1 -0
  45. package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/version-snapshot.ts +154 -0
  46. package/node_modules/@deterministic-code/deterministic-specifications-typescript/typescript/parser/yaml-node.ts +2 -2
  47. package/node_modules/@deterministic-code/rust-generators/dist/import-generator.js +25 -15
  48. package/node_modules/@deterministic-code/rust-generators/src/import-generator.test.ts +11 -0
  49. package/node_modules/@deterministic-code/rust-generators/src/import-generator.ts +36 -18
  50. package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-types.js +6 -1
  51. package/node_modules/@deterministic-code/typescript-generators/dist/generate-frontend-validators.js +6 -1
  52. package/node_modules/@deterministic-code/typescript-generators/dist/generate-routes.js +1 -1
  53. package/node_modules/@deterministic-code/typescript-generators/dist/generate-services.js +1 -1
  54. package/node_modules/@deterministic-code/typescript-generators/dist/import-generator.js +29 -21
  55. package/node_modules/@deterministic-code/typescript-generators/src/emit.ts +2 -5
  56. package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-types.ts +7 -1
  57. package/node_modules/@deterministic-code/typescript-generators/src/generate-frontend-validators.ts +7 -1
  58. package/node_modules/@deterministic-code/typescript-generators/src/generate-routes.ts +1 -1
  59. package/node_modules/@deterministic-code/typescript-generators/src/generate-services.ts +1 -1
  60. package/node_modules/@deterministic-code/typescript-generators/src/import-generator.test.ts +16 -0
  61. package/node_modules/@deterministic-code/typescript-generators/src/import-generator.ts +37 -22
  62. package/package.json +8 -8
@@ -1,33 +1,30 @@
1
1
  import { isAbsolute, join } from "node:path";
2
- import { generate as generateSql } from "@deterministic-code/datasources-code-generators/generate-sql";
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 listed = [
14
- ...new Set(
15
- loaded.settings["backend.datasources"].split(",").map((name) => name.trim()).filter((name) => name !== "")
16
- )
17
- ];
18
- if (command.migrationsPath !== void 0 && listed.length > 1)
19
- throw new Error("--migrations-path requires a single SQL dialect in backend.datasources");
20
- const entries = await generateSql({
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 remapped) deps.log(join(root, entry.filename));
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, remapped)) deps.log(path);
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
- const loaded = await loadSpec(deps.fs, at(flags.cwd, command.input));
43
- const dialects = sqlDialects(loaded.settings);
44
- const values = merged(await readEnv(deps.fs, flags.cwd), env);
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 backend.datasources (${dialects.join(", ") || "none"})`
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
+ };
@@ -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 migrateInitCommands = (dialects, language) => dialects.length === 0 ? [] : [
5
- { command: "npm", args: ["install", "@deterministic-code/migraters"] },
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
- "@deterministic-code/migraters",
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 [provider...] Interactive .env, provider install, and optional deterministic/
8
+ setup [name...] Interactive .env, datasource install, and optional deterministic/
7
9
  --cwd <dir> Consumer project directory (default: .)
8
- --ecosystem ts|rust|csharp Required when more than one project type exists
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 <provider...> Add provider packages
15
+ add [name...] Add datasource packages
13
16
  --cwd <dir> Consumer project directory (default: .)
14
- --ecosystem ts|rust|csharp Required when more than one project type exists
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 <provider...> Remove provider packages
21
+ remove [name...] Remove datasource packages
18
22
  --cwd <dir> Consumer project directory (default: .)
19
- --ecosystem ts|rust|csharp Required when more than one project type exists
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 Skip migrate-up (generate all applies them)
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
- migrationsPath: ""
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 === "--ecosystem") flags.ecosystem = ecosystem(argv[++i]);
69
- else if (arg.startsWith("--ecosystem=")) flags.ecosystem = ecosystem(arg.slice("--ecosystem=".length));
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 === "--migrations-path") generate.migrationsPath = take(argv, ++i, "--migrations-path");
86
- else if (arg.startsWith("--migrations-path=")) generate.migrationsPath = arg.slice("--migrations-path=".length);
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
- ...generate.migrationsPath === "" ? {} : { migrationsPath: generate.migrationsPath }
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
- ...generate.migrationsPath === "" ? {} : { migrationsPath: generate.migrationsPath }
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 ecosystem = (value) => value && isEcosystem(value) ? value : (() => {
144
- throw new Error(`Unknown --ecosystem ${value}. Use ts|rust|csharp`);
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 { catalog, requireProviders } from "./catalog.js";
2
+ import { requireProviders } from "./catalog.js";
4
3
  import { addCommands, removeCommands } from "./commands.js";
5
- import { csharpTarget, detect, resolveEcosystem } from "./detect.js";
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.migrationsPath === void 0 ? {} : { migrationsPath: command.migrationsPath }
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} <provider...>`);
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 = await readEnv(deps.fs, flags.cwd);
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), ecosystem: flags.ecosystem, scaffold: false } : await promptSetup(deps.prompt, existing, found, flags.ecosystem, missingSpec, requested);
67
- const ecosystem = resolveEcosystem(found, answers.ecosystem ?? flags.ecosystem);
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
- await applyPackages(
72
- flags,
73
- deps,
74
- ecosystem,
75
- entries,
76
- selected.filter((name) => !installed.includes(name)),
77
- installed.filter((name) => !selected.includes(name)),
78
- selected
79
- );
80
- await applyMigrateInit(flags, deps, ecosystem, selected);
81
- const dialect = migrateLanguage(ecosystem);
82
- await wireRegister(flags.cwd, "generated", dialect, flags.dryRun, deps);
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 ecosystem = resolveEcosystem(found, flags.ecosystem);
97
- const installed = await readInstalled(deps.fs, flags.cwd, ecosystem, entries);
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
- await applyPackages(flags, deps, ecosystem, entries, add, remove, remaining);
105
- await applyMigrateInit(flags, deps, ecosystem, remaining);
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
  };