@databricks-solutions/lakebase-scm-utils 0.2.51 → 0.3.1

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 (79) hide show
  1. package/README.md +10 -4
  2. package/dist/scripts/index.cjs +2813 -2244
  3. package/dist/scripts/index.d.cts +1 -1
  4. package/dist/scripts/index.d.ts +1 -1
  5. package/dist/scripts/index.js +857 -298
  6. package/dist/scripts/lakebase/ci-resolve-branch.cli.cjs +2460 -2030
  7. package/dist/scripts/lakebase/ci-resolve-branch.cli.js +508 -81
  8. package/dist/scripts/lakebase/collapse-heads.cli.cjs +2429 -2007
  9. package/dist/scripts/lakebase/collapse-heads.cli.js +477 -58
  10. package/dist/scripts/lakebase/detect-language.cli.cjs +2441 -2016
  11. package/dist/scripts/lakebase/detect-language.cli.js +489 -67
  12. package/dist/scripts/lakebase/doctor.cli.cjs +2484 -2040
  13. package/dist/scripts/lakebase/doctor.cli.js +532 -91
  14. package/dist/scripts/lakebase/get-connection.cli.cjs +2 -2
  15. package/dist/scripts/lakebase/get-connection.cli.js +2 -2
  16. package/dist/scripts/lakebase/index.cjs +2810 -2205
  17. package/dist/scripts/lakebase/index.d.cts +59 -10
  18. package/dist/scripts/lakebase/index.d.ts +59 -10
  19. package/dist/scripts/lakebase/index.js +851 -256
  20. package/dist/scripts/lakebase/infra-runner.cli.cjs +2435 -2013
  21. package/dist/scripts/lakebase/infra-runner.cli.js +483 -64
  22. package/dist/scripts/lakebase/new-migration.cli.cjs +2429 -2007
  23. package/dist/scripts/lakebase/new-migration.cli.js +477 -58
  24. package/dist/scripts/lakebase/schema-diff.cli.cjs +2 -2
  25. package/dist/scripts/lakebase/schema-diff.cli.js +2 -2
  26. package/dist/scripts/lakebase/schema-migrate.cli.cjs +2461 -2029
  27. package/dist/scripts/lakebase/schema-migrate.cli.js +509 -80
  28. package/dist/scripts/lakebase/scm-claim-feature.cli.cjs +2460 -2030
  29. package/dist/scripts/lakebase/scm-claim-feature.cli.js +508 -81
  30. package/dist/scripts/lakebase/scm-doctor.cli.cjs +2486 -2056
  31. package/dist/scripts/lakebase/scm-doctor.cli.js +537 -107
  32. package/dist/scripts/lakebase/scm-merge.cli.cjs +2443 -2021
  33. package/dist/scripts/lakebase/scm-merge.cli.js +494 -72
  34. package/dist/scripts/lakebase/scm-reconcile-tier.cli.cjs +2464 -2034
  35. package/dist/scripts/lakebase/scm-reconcile-tier.cli.js +511 -84
  36. package/dist/scripts/util/index.cjs +2 -2
  37. package/dist/scripts/util/index.js +2 -2
  38. package/package.json +1 -1
  39. package/scripts/lakebase/adapters/efcore-adapter.ts +158 -0
  40. package/scripts/lakebase/adapters/flyway-adapter.ts +8 -5
  41. package/scripts/lakebase/client-lockfile.ts +102 -0
  42. package/scripts/lakebase/collapse-heads.cli.ts +1 -1
  43. package/scripts/lakebase/create-project.ts +25 -2
  44. package/scripts/lakebase/detect-language.cli.ts +2 -2
  45. package/scripts/lakebase/doctor.ts +29 -0
  46. package/scripts/lakebase/dotnet-project.ts +112 -0
  47. package/scripts/lakebase/index.ts +1 -0
  48. package/scripts/lakebase/migration-layout.ts +43 -2
  49. package/scripts/lakebase/new-migration.cli.ts +1 -1
  50. package/scripts/lakebase/scaffold-language.ts +23 -2
  51. package/scripts/lakebase/scaffold.ts +4 -1
  52. package/scripts/lakebase/schema-migrate-runners/efcore.ts +399 -0
  53. package/scripts/lakebase/schema-migrate-runners/flyway.ts +6 -4
  54. package/scripts/lakebase/schema-migrate.cli.ts +3 -1
  55. package/scripts/lakebase/schema-migrate.ts +24 -10
  56. package/templates/project/common/.github/workflows/merge.yml +13 -1
  57. package/templates/project/common/.github/workflows/pr.yml +25 -5
  58. package/templates/project/common/scripts/flyway-migrate.sh +54 -1
  59. package/templates/project/common/scripts/prepare-schema-diff.sh +5 -0
  60. package/templates/project/common/scripts/run-dev.sh +10 -1
  61. package/templates/project/common/scripts/run-tests.sh +6 -1
  62. package/templates/project/dotnet/.gitignore.extra +8 -0
  63. package/templates/project/dotnet/App.sln +56 -0
  64. package/templates/project/dotnet/Makefile +13 -0
  65. package/templates/project/dotnet/global.json +6 -0
  66. package/templates/project/dotnet/src/App/Data/AppDbContext.cs +12 -0
  67. package/templates/project/dotnet/src/App/Lakebase/DotEnv.cs +48 -0
  68. package/templates/project/dotnet/src/App/Lakebase/LakebaseConnection.cs +225 -0
  69. package/templates/project/dotnet/src/App/Program.cs +34 -0
  70. package/templates/project/dotnet/src/App/appsettings.json +9 -0
  71. package/templates/project/dotnet/tests/App.Tests/App.Tests.csproj +25 -0
  72. package/templates/project/dotnet/tests/App.Tests/HealthTests.cs +18 -0
  73. package/templates/project/dotnet/tests/App.Tests/OpenApiTests.cs +23 -0
  74. package/templates/project/dotnet-efcore/.config/dotnet-tools.json +13 -0
  75. package/templates/project/dotnet-efcore/src/App/App.csproj +22 -0
  76. package/templates/project/dotnet-efcore/src/App/Data/DesignTimeDbContextFactory.cs +24 -0
  77. package/templates/project/dotnet-efcore/src/App/Migrations/README.md +23 -0
  78. package/templates/project/dotnet-flyway/db/migrations/README.md +23 -0
  79. package/templates/project/dotnet-flyway/src/App/App.csproj +17 -0
@@ -1457,7 +1457,7 @@ var require_light = __commonJS({
1457
1457
 
1458
1458
  // scripts/lakebase/scm-merge.cli.ts
1459
1459
  init_esm_shims();
1460
- import * as path14 from "path";
1460
+ import * as path17 from "path";
1461
1461
 
1462
1462
  // scripts/util/cli-entry.ts
1463
1463
  init_esm_shims();
@@ -2549,7 +2549,7 @@ paginateRest.VERSION = VERSION5;
2549
2549
 
2550
2550
  // node_modules/@octokit/plugin-paginate-graphql/dist-bundle/index.js
2551
2551
  init_esm_shims();
2552
- var generateMessage = (path15, cursorValue) => `The cursor at "${path15.join(
2552
+ var generateMessage = (path18, cursorValue) => `The cursor at "${path18.join(
2553
2553
  ","
2554
2554
  )}" did not change its value "${cursorValue}" after a page transition. Please make sure your that your query is set up correctly.`;
2555
2555
  var MissingCursorChange = class extends Error {
@@ -2590,9 +2590,9 @@ function findPaginatedResourcePath(responseData) {
2590
2590
  }
2591
2591
  return paginatedResourcePath;
2592
2592
  }
2593
- var deepFindPathToProperty = (object, searchProp, path15 = []) => {
2593
+ var deepFindPathToProperty = (object, searchProp, path18 = []) => {
2594
2594
  for (const key of Object.keys(object)) {
2595
- const currentPath = [...path15, key];
2595
+ const currentPath = [...path18, key];
2596
2596
  const currentValue = object[key];
2597
2597
  if (isObject(currentValue)) {
2598
2598
  if (currentValue.hasOwnProperty(searchProp)) {
@@ -2610,12 +2610,12 @@ var deepFindPathToProperty = (object, searchProp, path15 = []) => {
2610
2610
  }
2611
2611
  return [];
2612
2612
  };
2613
- var get = (object, path15) => {
2614
- return path15.reduce((current, nextProperty) => current[nextProperty], object);
2613
+ var get = (object, path18) => {
2614
+ return path18.reduce((current, nextProperty) => current[nextProperty], object);
2615
2615
  };
2616
- var set = (object, path15, mutator) => {
2617
- const lastProperty = path15[path15.length - 1];
2618
- const parentPath = [...path15].slice(0, -1);
2616
+ var set = (object, path18, mutator) => {
2617
+ const lastProperty = path18[path18.length - 1];
2618
+ const parentPath = [...path18].slice(0, -1);
2619
2619
  const parent = get(object, parentPath);
2620
2620
  if (typeof mutator === "function") {
2621
2621
  parent[lastProperty] = mutator(parent[lastProperty]);
@@ -2667,22 +2667,22 @@ var mergeResponses = (response1, response2) => {
2667
2667
  if (Object.keys(response1).length === 0) {
2668
2668
  return Object.assign(response1, response2);
2669
2669
  }
2670
- const path15 = findPaginatedResourcePath(response1);
2671
- const nodesPath = [...path15, "nodes"];
2670
+ const path18 = findPaginatedResourcePath(response1);
2671
+ const nodesPath = [...path18, "nodes"];
2672
2672
  const newNodes = get(response2, nodesPath);
2673
2673
  if (newNodes) {
2674
2674
  set(response1, nodesPath, (values) => {
2675
2675
  return [...values, ...newNodes];
2676
2676
  });
2677
2677
  }
2678
- const edgesPath = [...path15, "edges"];
2678
+ const edgesPath = [...path18, "edges"];
2679
2679
  const newEdges = get(response2, edgesPath);
2680
2680
  if (newEdges) {
2681
2681
  set(response1, edgesPath, (values) => {
2682
2682
  return [...values, ...newEdges];
2683
2683
  });
2684
2684
  }
2685
- const pageInfoPath = [...path15, "pageInfo"];
2685
+ const pageInfoPath = [...path18, "pageInfo"];
2686
2686
  set(response1, pageInfoPath, get(response2, pageInfoPath));
2687
2687
  return response1;
2688
2688
  };
@@ -5103,7 +5103,7 @@ var triggers_notification_paths_default = [
5103
5103
  ];
5104
5104
  function routeMatcher(paths) {
5105
5105
  const regexes = paths.map(
5106
- (path15) => path15.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5106
+ (path18) => path18.split("/").map((c) => c.startsWith("{") ? "(?:.+?)" : c).join("/")
5107
5107
  );
5108
5108
  const regex2 = `^(?:${regexes.map((r) => `(?:${r})`).join("|")})[^/]*$`;
5109
5109
  return new RegExp(regex2, "i");
@@ -8378,9 +8378,9 @@ function asBranchUid(s) {
8378
8378
  }
8379
8379
  return s;
8380
8380
  }
8381
- function branchNameFromResourcePath(path15) {
8382
- if (!path15.includes("/branches/")) return null;
8383
- const leaf = path15.split("/branches/").pop();
8381
+ function branchNameFromResourcePath(path18) {
8382
+ if (!path18.includes("/branches/")) return null;
8383
+ const leaf = path18.split("/branches/").pop();
8384
8384
  if (!leaf) return null;
8385
8385
  try {
8386
8386
  return asBranchName(leaf);
@@ -9951,8 +9951,8 @@ function shellEscape(s) {
9951
9951
 
9952
9952
  // scripts/lakebase/schema-migrate.ts
9953
9953
  init_esm_shims();
9954
- import * as fs11 from "fs";
9955
- import * as path13 from "path";
9954
+ import * as fs13 from "fs";
9955
+ import * as path16 from "path";
9956
9956
 
9957
9957
  // scripts/lakebase/get-connection.ts
9958
9958
  init_esm_shims();
@@ -9978,8 +9978,8 @@ var PKG_NAME = "@databricks-solutions/lakebase-scm-utils";
9978
9978
  var cached;
9979
9979
  function substrateSelfVersion() {
9980
9980
  if (cached !== void 0) return cached;
9981
- if ("0.2.51".length > 0) {
9982
- cached = "0.2.51";
9981
+ if ("0.3.1".length > 0) {
9982
+ cached = "0.3.1";
9983
9983
  return cached;
9984
9984
  }
9985
9985
  cached = "unknown";
@@ -10090,24 +10090,87 @@ function dbcli3(args) {
10090
10090
  // scripts/lakebase/migration-layout.ts
10091
10091
  init_esm_shims();
10092
10092
 
10093
+ // scripts/lakebase/dotnet-project.ts
10094
+ init_esm_shims();
10095
+ import * as fs6 from "fs";
10096
+ import * as path7 from "path";
10097
+ var EF_DESIGN_PACKAGE = "Microsoft.EntityFrameworkCore.Design";
10098
+ var DOTNET_FLYWAY_DIR = path7.join("db", "migrations");
10099
+ var SKIP_DIRS = /* @__PURE__ */ new Set(["bin", "obj", "node_modules", ".git", "client", "tests", "test"]);
10100
+ function safeReaddir(dir) {
10101
+ try {
10102
+ return fs6.readdirSync(dir, { withFileTypes: true });
10103
+ } catch {
10104
+ return [];
10105
+ }
10106
+ }
10107
+ function hasDotnetMarker(dir) {
10108
+ return safeReaddir(dir).some(
10109
+ (e) => e.isFile() && /\.(sln|slnx|csproj)$/i.test(e.name)
10110
+ );
10111
+ }
10112
+ function findCsprojFiles(projectDir) {
10113
+ const found = [];
10114
+ const walk = (dir, depth) => {
10115
+ for (const e of safeReaddir(dir)) {
10116
+ const full = path7.join(dir, e.name);
10117
+ if (e.isFile() && e.name.toLowerCase().endsWith(".csproj")) {
10118
+ found.push(full);
10119
+ } else if (e.isDirectory() && depth < 2 && !SKIP_DIRS.has(e.name.toLowerCase()) && !e.name.startsWith(".")) {
10120
+ walk(full, depth + 1);
10121
+ }
10122
+ }
10123
+ };
10124
+ walk(projectDir, 0);
10125
+ return found.sort();
10126
+ }
10127
+ function findEfCoreProject(projectDir) {
10128
+ for (const csproj of findCsprojFiles(projectDir)) {
10129
+ let content = "";
10130
+ try {
10131
+ content = fs6.readFileSync(csproj, "utf-8");
10132
+ } catch {
10133
+ continue;
10134
+ }
10135
+ if (content.includes(EF_DESIGN_PACKAGE)) {
10136
+ const dir = path7.dirname(csproj);
10137
+ return { csproj, projectDir: dir, migrationsDir: path7.join(dir, "Migrations") };
10138
+ }
10139
+ }
10140
+ return null;
10141
+ }
10142
+ function isDotnetProject(projectDir) {
10143
+ return hasDotnetMarker(projectDir);
10144
+ }
10145
+ function isDotnetFlywayProject(projectDir) {
10146
+ return isDotnetProject(projectDir) && fs6.existsSync(path7.join(projectDir, DOTNET_FLYWAY_DIR));
10147
+ }
10148
+ var MAVEN_FLYWAY_DIR = path7.join("src", "main", "resources", "db", "migration");
10149
+ function flywayMigrationsDir(projectDir) {
10150
+ const maven = path7.join(projectDir, MAVEN_FLYWAY_DIR);
10151
+ if (fs6.existsSync(maven) || fs6.existsSync(path7.join(projectDir, "pom.xml"))) return maven;
10152
+ if (isDotnetFlywayProject(projectDir)) return path7.join(projectDir, DOTNET_FLYWAY_DIR);
10153
+ return maven;
10154
+ }
10155
+
10093
10156
  // scripts/lakebase/adapters/alembic-adapter.ts
10094
10157
  init_esm_shims();
10095
- import * as fs7 from "fs";
10096
- import * as path8 from "path";
10158
+ import * as fs8 from "fs";
10159
+ import * as path9 from "path";
10097
10160
 
10098
10161
  // scripts/lakebase/schema-migrate-runners/alembic.ts
10099
10162
  init_esm_shims();
10100
10163
  import { spawn } from "child_process";
10101
- import * as fs6 from "fs";
10102
- import * as path7 from "path";
10164
+ import * as fs7 from "fs";
10165
+ import * as path8 from "path";
10103
10166
  function resolveAlembicBin(projectDir) {
10104
10167
  const candidates = [
10105
- path7.join(projectDir, ".venv", "bin", "alembic"),
10106
- path7.join(projectDir, "venv", "bin", "alembic")
10168
+ path8.join(projectDir, ".venv", "bin", "alembic"),
10169
+ path8.join(projectDir, "venv", "bin", "alembic")
10107
10170
  ];
10108
10171
  for (const candidate of candidates) {
10109
10172
  try {
10110
- if (fs6.existsSync(candidate)) return candidate;
10173
+ if (fs7.existsSync(candidate)) return candidate;
10111
10174
  } catch {
10112
10175
  }
10113
10176
  }
@@ -10117,7 +10180,7 @@ function spawnAlembic(projectDir, args, dsn) {
10117
10180
  return new Promise((resolve2, reject) => {
10118
10181
  const bin = resolveAlembicBin(projectDir);
10119
10182
  const env = { ...process.env };
10120
- env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path7.delimiter);
10183
+ env.PYTHONPATH = [projectDir, process.env.PYTHONPATH].filter(Boolean).join(path8.delimiter);
10121
10184
  if (dsn) env.DATABASE_URL = dsn;
10122
10185
  const child = spawn(bin, args, {
10123
10186
  cwd: projectDir,
@@ -10165,10 +10228,10 @@ async function createAlembicRevision(opts) {
10165
10228
  const m = stdout.match(/Generating\s+(\S+\.py)/);
10166
10229
  if (m) return m[1].trim();
10167
10230
  for (const rel of ["migrations/versions", "alembic/versions"]) {
10168
- const dir = path7.join(opts.projectDir, rel);
10169
- if (!fs6.existsSync(dir)) continue;
10170
- const hit = fs6.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
10171
- if (hit) return path7.join(dir, hit);
10231
+ const dir = path8.join(opts.projectDir, rel);
10232
+ if (!fs7.existsSync(dir)) continue;
10233
+ const hit = fs7.readdirSync(dir).find((f) => f.startsWith(`${opts.revId}_`) && f.endsWith(".py"));
10234
+ if (hit) return path8.join(dir, hit);
10172
10235
  }
10173
10236
  throw new SchemaMigrationError(
10174
10237
  `alembic revision succeeded but the created file could not be located.
@@ -10303,15 +10366,15 @@ async function buildDsn(args) {
10303
10366
  }
10304
10367
  function findVersionsDir(projectDir) {
10305
10368
  const candidates = [
10306
- path8.join(projectDir, "migrations", "versions"),
10307
- path8.join(projectDir, "alembic", "versions")
10369
+ path9.join(projectDir, "migrations", "versions"),
10370
+ path9.join(projectDir, "alembic", "versions")
10308
10371
  ];
10309
- return candidates.find((p) => fs7.existsSync(p));
10372
+ return candidates.find((p) => fs8.existsSync(p));
10310
10373
  }
10311
10374
  function listAlembicFiles(projectDir) {
10312
10375
  const dir = findVersionsDir(projectDir);
10313
10376
  if (!dir) return [];
10314
- const files = fs7.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
10377
+ const files = fs8.readdirSync(dir).filter((f) => f.endsWith(".py") && !f.startsWith("__"));
10315
10378
  return files.map((filename) => {
10316
10379
  const stem = filename.replace(/\.py$/, "");
10317
10380
  const sep2 = stem.indexOf("_");
@@ -10336,9 +10399,9 @@ var AlembicAdapter = {
10336
10399
  * here. Callers can still force-select via project.yaml#migration_tool.
10337
10400
  */
10338
10401
  detect(projectDir) {
10339
- if (fs7.existsSync(path8.join(projectDir, "alembic.ini"))) return true;
10340
- if (fs7.existsSync(path8.join(projectDir, "migrations", "env.py"))) return true;
10341
- if (fs7.existsSync(path8.join(projectDir, "alembic", "env.py"))) return true;
10402
+ if (fs8.existsSync(path9.join(projectDir, "alembic.ini"))) return true;
10403
+ if (fs8.existsSync(path9.join(projectDir, "migrations", "env.py"))) return true;
10404
+ if (fs8.existsSync(path9.join(projectDir, "alembic", "env.py"))) return true;
10342
10405
  return false;
10343
10406
  },
10344
10407
  async apply(args) {
@@ -10444,7 +10507,7 @@ var AlembicAdapter = {
10444
10507
  autogenerate: !!args.autogenerate,
10445
10508
  dsn
10446
10509
  });
10447
- return { status: "ok", version: revId, filename: path8.basename(created), path: created };
10510
+ return { status: "ok", version: revId, filename: path9.basename(created), path: created };
10448
10511
  } catch (err) {
10449
10512
  return {
10450
10513
  status: "error",
@@ -10461,7 +10524,7 @@ var AlembicAdapter = {
10461
10524
  if (heads.length <= 1) return { status: "noop", headsBefore: heads };
10462
10525
  if (args.dryRun) return { status: "ok", headsBefore: heads };
10463
10526
  const created = await mergeAlembicHeads(args.projectDir, args.message ?? "merge heads");
10464
- const mergeRevision = path8.basename(created).replace(/\.py$/, "").split("_")[0];
10527
+ const mergeRevision = path9.basename(created).replace(/\.py$/, "").split("_")[0];
10465
10528
  return { status: "ok", headsBefore: heads, mergeRevision, path: created };
10466
10529
  } catch (err) {
10467
10530
  return {
@@ -10476,13 +10539,13 @@ registerSchemaMigrationAdapter(AlembicAdapter);
10476
10539
 
10477
10540
  // scripts/lakebase/adapters/flyway-adapter.ts
10478
10541
  init_esm_shims();
10479
- import * as fs8 from "fs";
10480
- import * as path10 from "path";
10542
+ import * as fs9 from "fs";
10543
+ import * as path11 from "path";
10481
10544
 
10482
10545
  // scripts/lakebase/schema-migrate-runners/flyway.ts
10483
10546
  init_esm_shims();
10484
10547
  import { spawn as spawn2 } from "child_process";
10485
- import * as path9 from "path";
10548
+ import * as path10 from "path";
10486
10549
  function dsnToFlywayEnv(dsn) {
10487
10550
  const u = new URL(dsn);
10488
10551
  const user = decodeURIComponent(u.username);
@@ -10492,7 +10555,7 @@ function dsnToFlywayEnv(dsn) {
10492
10555
  return { url, user, password };
10493
10556
  }
10494
10557
  function migrationsLocation(projectDir) {
10495
- return `filesystem:${path9.join(projectDir, "src", "main", "resources", "db", "migration")}`;
10558
+ return `filesystem:${flywayMigrationsDir(projectDir)}`;
10496
10559
  }
10497
10560
  function runFlyway(ctx, args) {
10498
10561
  const { url, user, password } = dsnToFlywayEnv(ctx.dsn);
@@ -10593,7 +10656,7 @@ async function statusFlyway(ctx) {
10593
10656
  if (state === "SUCCESS" || state === "BASELINE") {
10594
10657
  current = m.version;
10595
10658
  } else if (state === "PENDING") {
10596
- const filename = m.filepath ? path9.basename(m.filepath) : `V${m.version}__migration.sql`;
10659
+ const filename = m.filepath ? path10.basename(m.filepath) : `V${m.version}__migration.sql`;
10597
10660
  pending.push({
10598
10661
  version: m.version,
10599
10662
  filename,
@@ -10616,9 +10679,9 @@ async function buildDsn2(args) {
10616
10679
  return result.url;
10617
10680
  }
10618
10681
  function listFlywayFiles(projectDir) {
10619
- const dir = path10.join(projectDir, "src", "main", "resources", "db", "migration");
10620
- if (!fs8.existsSync(dir)) return [];
10621
- const files = fs8.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
10682
+ const dir = flywayMigrationsDir(projectDir);
10683
+ if (!fs9.existsSync(dir)) return [];
10684
+ const files = fs9.readdirSync(dir).filter((f) => /^V\d+(\.\d+)*__.+\.sql$/.test(f));
10622
10685
  return files.map((filename) => {
10623
10686
  const m = filename.match(/^V(\d+(?:\.\d+)*)__(.+)\.sql$/);
10624
10687
  const version = m[1];
@@ -10639,9 +10702,9 @@ function versionCompare(a, b) {
10639
10702
  }
10640
10703
  var FlywayAdapter = {
10641
10704
  id: "flyway",
10642
- languages: ["java", "kotlin"],
10705
+ languages: ["java", "kotlin", "dotnet"],
10643
10706
  detect(projectDir) {
10644
- return fs8.existsSync(path10.join(projectDir, "pom.xml"));
10707
+ return fs9.existsSync(path11.join(projectDir, "pom.xml")) || isDotnetFlywayProject(projectDir);
10645
10708
  },
10646
10709
  async apply(args) {
10647
10710
  const dsn = await buildDsn2(args);
@@ -10699,14 +10762,14 @@ var FlywayAdapter = {
10699
10762
  // optional-protocol shape makes this additive.
10700
10763
  async newMigration(args) {
10701
10764
  try {
10702
- const dir = path10.join(args.projectDir, "src", "main", "resources", "db", "migration");
10703
- fs8.mkdirSync(dir, { recursive: true });
10765
+ const dir = flywayMigrationsDir(args.projectDir);
10766
+ fs9.mkdirSync(dir, { recursive: true });
10704
10767
  const version = migrationTimestamp();
10705
10768
  const slug = migrationSlug2(args.slug);
10706
10769
  const filename = `V${version}__${slug}.sql`;
10707
- const full = path10.join(dir, filename);
10708
- if (fs8.existsSync(full)) throw new Error(`${filename} already exists`);
10709
- fs8.writeFileSync(
10770
+ const full = path11.join(dir, filename);
10771
+ if (fs9.existsSync(full)) throw new Error(`${filename} already exists`);
10772
+ fs9.writeFileSync(
10710
10773
  full,
10711
10774
  `-- V${version}: ${args.slug}
10712
10775
  -- Flyway migration (write your DDL/DML below).
@@ -10729,19 +10792,19 @@ registerSchemaMigrationAdapter(FlywayAdapter);
10729
10792
 
10730
10793
  // scripts/lakebase/adapters/knex-adapter.ts
10731
10794
  init_esm_shims();
10732
- import * as fs10 from "fs";
10733
- import * as path12 from "path";
10795
+ import * as fs11 from "fs";
10796
+ import * as path13 from "path";
10734
10797
 
10735
10798
  // scripts/lakebase/schema-migrate-runners/knex.ts
10736
10799
  init_esm_shims();
10737
10800
  import { spawn as spawn3 } from "child_process";
10738
- import * as fs9 from "fs";
10739
- import * as path11 from "path";
10801
+ import * as fs10 from "fs";
10802
+ import * as path12 from "path";
10740
10803
  var KNEXFILE_VARIANTS = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10741
10804
  function findKnexfile(projectDir) {
10742
10805
  for (const name of KNEXFILE_VARIANTS) {
10743
- const p = path11.join(projectDir, name);
10744
- if (fs9.existsSync(p)) return p;
10806
+ const p = path12.join(projectDir, name);
10807
+ if (fs10.existsSync(p)) return p;
10745
10808
  }
10746
10809
  return void 0;
10747
10810
  }
@@ -10893,9 +10956,9 @@ async function buildDsn3(args) {
10893
10956
  }
10894
10957
  var KNEXFILE_VARIANTS2 = ["knexfile.js", "knexfile.ts", "knexfile.mjs", "knexfile.cjs"];
10895
10958
  function listKnexFiles(projectDir) {
10896
- const dir = path12.join(projectDir, "migrations");
10897
- if (!fs10.existsSync(dir)) return [];
10898
- const files = fs10.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
10959
+ const dir = path13.join(projectDir, "migrations");
10960
+ if (!fs11.existsSync(dir)) return [];
10961
+ const files = fs11.readdirSync(dir).filter((f) => (f.endsWith(".js") || f.endsWith(".ts")) && !f.startsWith("."));
10899
10962
  return files.map((filename) => {
10900
10963
  const stem = filename.replace(/\.(js|ts)$/, "");
10901
10964
  const m = stem.match(/^(\d{14})_(.+)$/);
@@ -10915,7 +10978,7 @@ var KnexAdapter = {
10915
10978
  * project.yaml#migration_tool.
10916
10979
  */
10917
10980
  detect(projectDir) {
10918
- return KNEXFILE_VARIANTS2.some((name) => fs10.existsSync(path12.join(projectDir, name)));
10981
+ return KNEXFILE_VARIANTS2.some((name) => fs11.existsSync(path13.join(projectDir, name)));
10919
10982
  },
10920
10983
  async apply(args) {
10921
10984
  const dsn = await buildDsn3(args);
@@ -10988,9 +11051,9 @@ var KnexAdapter = {
10988
11051
  async newMigration(args) {
10989
11052
  try {
10990
11053
  const created = await createKnexMigration({ projectDir: args.projectDir, slug: migrationSlug2(args.slug) });
10991
- const stem = path12.basename(created).replace(/\.(js|ts)$/, "");
11054
+ const stem = path13.basename(created).replace(/\.(js|ts)$/, "");
10992
11055
  const version = stem.match(/^(\d{14})_/)?.[1] ?? stem;
10993
- return { status: "ok", version, filename: path12.basename(created), path: created };
11056
+ return { status: "ok", version, filename: path13.basename(created), path: created };
10994
11057
  } catch (err) {
10995
11058
  return {
10996
11059
  status: "error",
@@ -11004,6 +11067,362 @@ var KnexAdapter = {
11004
11067
  };
11005
11068
  registerSchemaMigrationAdapter(KnexAdapter);
11006
11069
 
11070
+ // scripts/lakebase/adapters/efcore-adapter.ts
11071
+ init_esm_shims();
11072
+ import * as path15 from "path";
11073
+
11074
+ // scripts/lakebase/schema-migrate-runners/efcore.ts
11075
+ init_esm_shims();
11076
+ import { spawn as spawn4 } from "child_process";
11077
+ import * as fs12 from "fs";
11078
+ import * as path14 from "path";
11079
+ import { Client as Client2 } from "pg";
11080
+ var MIGRATION_ID = /^(\d{14})_(.+)$/;
11081
+ function efVersion(id) {
11082
+ return MIGRATION_ID.exec(id)?.[1] ?? id;
11083
+ }
11084
+ function efDescription(id) {
11085
+ const name = MIGRATION_ID.exec(id)?.[2] ?? id;
11086
+ return name.replace(/_/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2");
11087
+ }
11088
+ function dsnToNpgsql(dsn) {
11089
+ const u = new URL(dsn);
11090
+ const parts = [
11091
+ `Host=${u.hostname}`,
11092
+ `Port=${u.port || "5432"}`,
11093
+ `Database=${decodeURIComponent(u.pathname.replace(/^\//, "")) || "databricks_postgres"}`
11094
+ ];
11095
+ if (u.username) parts.push(`Username=${decodeURIComponent(u.username)}`);
11096
+ if (u.password) parts.push(`Password=${decodeURIComponent(u.password)}`);
11097
+ const sslmode = (u.searchParams.get("sslmode") ?? "require").toLowerCase();
11098
+ const ssl = {
11099
+ disable: "Disable",
11100
+ allow: "Allow",
11101
+ prefer: "Prefer",
11102
+ require: "Require",
11103
+ "verify-ca": "VerifyCA",
11104
+ "verify-full": "VerifyFull"
11105
+ };
11106
+ parts.push(`SSL Mode=${ssl[sslmode] ?? "Require"}`);
11107
+ const app = u.searchParams.get("application_name");
11108
+ if (app) parts.push(`Application Name=${app}`);
11109
+ return parts.map((p) => p.replace(/;/g, "")).join(";");
11110
+ }
11111
+ function parseEfJson(stdout) {
11112
+ const body = stdout.split(/\r?\n/).filter((l) => l.startsWith("data:")).map((l) => l.slice("data:".length)).join("\n").trim();
11113
+ if (!body) {
11114
+ throw new SchemaMigrationError(`dotnet ef returned no JSON payload: ${stdout.slice(0, 400)}`);
11115
+ }
11116
+ try {
11117
+ return JSON.parse(body);
11118
+ } catch (err) {
11119
+ throw new SchemaMigrationError(
11120
+ `dotnet ef JSON parse failed: ${err instanceof Error ? err.message : String(err)}.
11121
+ Body (first 400 chars): ${body.slice(0, 400)}`
11122
+ );
11123
+ }
11124
+ }
11125
+ function requireProject(projectDir) {
11126
+ const project = findEfCoreProject(projectDir);
11127
+ if (!project) {
11128
+ throw new SchemaMigrationError(
11129
+ `No EF Core project found under ${projectDir}. Expected a *.csproj that references ${EF_DESIGN_PACKAGE}.`
11130
+ );
11131
+ }
11132
+ return project;
11133
+ }
11134
+ function spawnDotnet(projectDir, args, env) {
11135
+ return new Promise((resolve2, reject) => {
11136
+ const child = spawn4("dotnet", args, {
11137
+ cwd: projectDir,
11138
+ env: { ...process.env, DOTNET_NOLOGO: "1", DOTNET_CLI_TELEMETRY_OPTOUT: "1", ...env },
11139
+ stdio: ["ignore", "pipe", "pipe"]
11140
+ });
11141
+ let stdout = "";
11142
+ let stderr = "";
11143
+ child.stdout.on("data", (chunk) => {
11144
+ stdout += chunk.toString("utf8");
11145
+ });
11146
+ child.stderr.on("data", (chunk) => {
11147
+ stderr += chunk.toString("utf8");
11148
+ });
11149
+ child.on("error", (err) => {
11150
+ reject(
11151
+ new SchemaMigrationError(
11152
+ `Could not spawn dotnet. Is the .NET SDK installed and on PATH? ${err.message}`,
11153
+ err
11154
+ )
11155
+ );
11156
+ });
11157
+ child.on("close", (code) => {
11158
+ if (code === 0) {
11159
+ resolve2({ stdout, stderr });
11160
+ } else {
11161
+ reject(
11162
+ new SchemaMigrationError(
11163
+ `dotnet ${args.join(" ")} exited with code ${code}.
11164
+ stdout: ${stdout}
11165
+ stderr: ${stderr}`
11166
+ )
11167
+ );
11168
+ }
11169
+ });
11170
+ });
11171
+ }
11172
+ var restored = /* @__PURE__ */ new Set();
11173
+ async function ensureRestored(projectDir, csproj) {
11174
+ if (restored.has(projectDir)) return;
11175
+ if (fs12.existsSync(path14.join(projectDir, ".config", "dotnet-tools.json"))) {
11176
+ await spawnDotnet(projectDir, ["tool", "restore"], {});
11177
+ }
11178
+ await spawnDotnet(projectDir, ["restore", csproj], {});
11179
+ restored.add(projectDir);
11180
+ }
11181
+ async function runEf(projectDir, args, dsn, opts = {}) {
11182
+ const project = requireProject(projectDir);
11183
+ const csproj = path14.relative(projectDir, project.csproj) || project.csproj;
11184
+ await ensureRestored(projectDir, csproj);
11185
+ const full = ["ef", ...args, "--project", csproj, "--prefix-output"];
11186
+ if (opts.noBuild) full.push("--no-build");
11187
+ const env = {};
11188
+ if (dsn) {
11189
+ env.DATABASE_URL = dsn;
11190
+ if (process.env.LAKEBASE_EFCORE_CONNECTION_ARG === "1") full.push("--connection", dsnToNpgsql(dsn));
11191
+ }
11192
+ return spawnDotnet(projectDir, full, env);
11193
+ }
11194
+ async function listEfMigrations(ctx, opts = {}) {
11195
+ const { stdout, stderr } = await runEf(ctx.projectDir, ["migrations", "list", "--json"], ctx.dsn, opts);
11196
+ const entries = parseEfJson(stdout);
11197
+ if (ctx.dsn && entries.some((e) => e.applied === null)) {
11198
+ const warning = stdout.split(/\r?\n/).filter((l) => /^(warn|error):/.test(l)).join("\n");
11199
+ throw new SchemaMigrationError(
11200
+ `dotnet ef could not read migration state from the database (check connectivity and credentials).
11201
+ ${warning || stderr}`.trim()
11202
+ );
11203
+ }
11204
+ return entries;
11205
+ }
11206
+ async function readEfHistory(dsn) {
11207
+ const client = new Client2({ connectionString: dsn, application_name: connectionApplicationName() });
11208
+ await client.connect();
11209
+ try {
11210
+ const exists = await client.query(`SELECT to_regclass('"__EFMigrationsHistory"') IS NOT NULL AS present`);
11211
+ if (!exists.rows[0]?.present) return null;
11212
+ const r = await client.query(`SELECT "MigrationId" FROM "__EFMigrationsHistory" ORDER BY "MigrationId"`);
11213
+ return r.rows.map((row) => row.MigrationId);
11214
+ } finally {
11215
+ await client.end();
11216
+ }
11217
+ }
11218
+ function toApplied(entries) {
11219
+ return entries.map((e) => ({ version: efVersion(e.id), description: efDescription(e.id) }));
11220
+ }
11221
+ async function statusEfcore(ctx) {
11222
+ const entries = await listEfMigrations(ctx);
11223
+ const history = await (ctx.readHistory ?? readEfHistory)(ctx.dsn);
11224
+ const current = history && history.length > 0 ? efVersion(history[history.length - 1]) : void 0;
11225
+ const pending = entries.filter((e) => e.applied !== true).map((e) => ({ version: efVersion(e.id), filename: `${e.id}.cs`, description: efDescription(e.id) }));
11226
+ return { current, pending, tool: "efcore" };
11227
+ }
11228
+ async function applyEfcore(ctx) {
11229
+ const before = new Set((await listEfMigrations(ctx)).filter((e) => e.applied).map((e) => e.id));
11230
+ await runEf(ctx.projectDir, ["database", "update"], ctx.dsn, { noBuild: true });
11231
+ const after = await listEfMigrations(ctx, { noBuild: true });
11232
+ const applied = toApplied(after.filter((e) => e.applied && !before.has(e.id)));
11233
+ return { applied, alreadyAtLatest: applied.length === 0, tool: "efcore" };
11234
+ }
11235
+ function resolveEfTarget(target, applied) {
11236
+ const t = target.trim();
11237
+ if (t === "0") return "0";
11238
+ const rel = /^-(\d+)$/.exec(t);
11239
+ if (rel) {
11240
+ const steps = Number(rel[1]);
11241
+ if (steps < 1) throw new SchemaMigrationError(`Invalid rollback step: ${target}`);
11242
+ const index = applied.length - 1 - steps;
11243
+ if (index < -1) {
11244
+ throw new SchemaMigrationError(`Cannot roll back ${steps} migration(s); only ${applied.length} applied.`);
11245
+ }
11246
+ return index === -1 ? "0" : applied[index].id;
11247
+ }
11248
+ const match = applied.find((e) => e.id === t || efVersion(e.id) === t || e.name === t);
11249
+ if (!match) throw new SchemaMigrationError(`Rollback target '${target}' is not an applied migration.`);
11250
+ return match.id;
11251
+ }
11252
+ async function rollbackEfcore(ctx) {
11253
+ const beforeEntries = (await listEfMigrations(ctx)).filter((e) => e.applied);
11254
+ const targetId = resolveEfTarget(ctx.target, beforeEntries);
11255
+ await runEf(ctx.projectDir, ["database", "update", targetId], ctx.dsn, { noBuild: true });
11256
+ const stillApplied = new Set((await listEfMigrations(ctx, { noBuild: true })).filter((e) => e.applied).map((e) => e.id));
11257
+ return { rolledBack: toApplied(beforeEntries.filter((e) => !stillApplied.has(e.id)).reverse()), tool: "efcore" };
11258
+ }
11259
+ function efMigrationName(slug) {
11260
+ const name = slug.split(/[^A-Za-z0-9]+/).filter(Boolean).map((w) => w[0].toUpperCase() + w.slice(1)).join("");
11261
+ if (!name) throw new SchemaMigrationError(`Cannot derive a migration name from '${slug}'.`);
11262
+ return /^[0-9]/.test(name) ? `M${name}` : name;
11263
+ }
11264
+ async function createEfcoreMigration(opts) {
11265
+ const project = requireProject(opts.projectDir);
11266
+ const name = efMigrationName(opts.slug);
11267
+ const existing = new Set(fs12.existsSync(project.migrationsDir) ? fs12.readdirSync(project.migrationsDir) : []);
11268
+ await runEf(opts.projectDir, ["migrations", "add", name]);
11269
+ const created = fs12.readdirSync(project.migrationsDir).filter((f) => !existing.has(f) && MIGRATION_ID.test(f.replace(/\.cs$/, "")) && !f.endsWith(".Designer.cs"));
11270
+ if (created.length !== 1) {
11271
+ throw new SchemaMigrationError(`Expected one new migration file for ${name}, found: ${created.join(", ") || "none"}`);
11272
+ }
11273
+ return { id: created[0].replace(/\.cs$/, ""), path: path14.join(project.migrationsDir, created[0]) };
11274
+ }
11275
+ function localEfMigrationIds(projectDir) {
11276
+ const project = findEfCoreProject(projectDir);
11277
+ if (!project || !fs12.existsSync(project.migrationsDir)) return [];
11278
+ return fs12.readdirSync(project.migrationsDir).filter((f) => f.endsWith(".cs") && !f.endsWith(".Designer.cs") && MIGRATION_ID.test(f.slice(0, -3))).map((f) => f.slice(0, -3)).sort();
11279
+ }
11280
+ function efProductVersion(project) {
11281
+ try {
11282
+ const csproj = fs12.readFileSync(project.csproj, "utf-8");
11283
+ const m = new RegExp(`${EF_DESIGN_PACKAGE.replace(/\./g, "\\.")}"\\s+Version="([^"]+)"`).exec(csproj);
11284
+ if (m) return m[1];
11285
+ } catch {
11286
+ }
11287
+ return "unknown";
11288
+ }
11289
+ async function stampEfcore(ctx) {
11290
+ const project = requireProject(ctx.projectDir);
11291
+ const ids = localEfMigrationIds(ctx.projectDir);
11292
+ if (ids.length === 0) throw new SchemaMigrationError("No local EF Core migrations to stamp.");
11293
+ const rev = ctx.revision.trim();
11294
+ const end = rev === "head" ? ids.length - 1 : ids.findIndex((id) => id === rev || efVersion(id) === rev);
11295
+ if (end < 0) throw new SchemaMigrationError(`Stamp revision '${ctx.revision}' is not a local migration.`);
11296
+ const toStamp = ids.slice(0, end + 1);
11297
+ const productVersion = efProductVersion(project);
11298
+ const client = new Client2({ connectionString: ctx.dsn, application_name: connectionApplicationName() });
11299
+ await client.connect();
11300
+ try {
11301
+ await client.query("BEGIN");
11302
+ await client.query(
11303
+ `CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
11304
+ "MigrationId" character varying(150) NOT NULL,
11305
+ "ProductVersion" character varying(32) NOT NULL,
11306
+ CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId"))`
11307
+ );
11308
+ await client.query(`DELETE FROM "__EFMigrationsHistory" WHERE NOT ("MigrationId" = ANY($1::text[]))`, [toStamp]);
11309
+ for (const id of toStamp) {
11310
+ await client.query(
11311
+ `INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ($1, $2)
11312
+ ON CONFLICT ("MigrationId") DO NOTHING`,
11313
+ [id, productVersion]
11314
+ );
11315
+ }
11316
+ await client.query("COMMIT");
11317
+ } catch (err) {
11318
+ await client.query("ROLLBACK").catch(() => void 0);
11319
+ throw err;
11320
+ } finally {
11321
+ await client.end();
11322
+ }
11323
+ return efVersion(toStamp[toStamp.length - 1]);
11324
+ }
11325
+
11326
+ // scripts/lakebase/adapters/efcore-adapter.ts
11327
+ async function buildDsn4(args) {
11328
+ const result = await getConnection({
11329
+ output: "dsn",
11330
+ instance: args.instance,
11331
+ branch: args.branch,
11332
+ database: args.database,
11333
+ endpointName: args.endpointName
11334
+ });
11335
+ return result.url;
11336
+ }
11337
+ function errMsg(err) {
11338
+ return err instanceof Error ? err.message : String(err);
11339
+ }
11340
+ function listEfCoreFiles(projectDir) {
11341
+ return localEfMigrationIds(projectDir).map((id) => ({
11342
+ version: efVersion(id),
11343
+ filename: `${id}.cs`,
11344
+ description: efDescription(id),
11345
+ type: "CSharp",
11346
+ tool: "efcore"
11347
+ }));
11348
+ }
11349
+ var EfCoreAdapter = {
11350
+ id: "efcore",
11351
+ languages: ["dotnet"],
11352
+ /** A .NET project (root marker) with a *.csproj that references Microsoft.EntityFrameworkCore.Design. */
11353
+ detect(projectDir) {
11354
+ return isDotnetProject(projectDir) && findEfCoreProject(projectDir) !== null;
11355
+ },
11356
+ async apply(args) {
11357
+ try {
11358
+ const dsn = await buildDsn4(args);
11359
+ const r = await applyEfcore({ projectDir: args.projectDir, dsn });
11360
+ return {
11361
+ applied_migrations: r.applied,
11362
+ status: r.alreadyAtLatest ? "noop" : "ok",
11363
+ tool_specific: { alreadyAtLatest: r.alreadyAtLatest, tool: r.tool }
11364
+ };
11365
+ } catch (err) {
11366
+ return { applied_migrations: [], status: "error", error: errMsg(err) };
11367
+ }
11368
+ },
11369
+ async rollback(args) {
11370
+ try {
11371
+ const dsn = await buildDsn4(args);
11372
+ const r = await rollbackEfcore({ projectDir: args.projectDir, dsn, target: args.target });
11373
+ return {
11374
+ rolled_back: r.rolledBack,
11375
+ status: r.rolledBack.length === 0 ? "noop" : "ok",
11376
+ tool_specific: { tool: r.tool }
11377
+ };
11378
+ } catch (err) {
11379
+ return { rolled_back: [], status: "error", error: errMsg(err) };
11380
+ }
11381
+ },
11382
+ async stamp(args) {
11383
+ try {
11384
+ const dsn = await buildDsn4(args);
11385
+ const stamped = await stampEfcore({ projectDir: args.projectDir, dsn, revision: args.revision });
11386
+ return { status: "ok", stamped_revision: stamped, tool_specific: { tool: "efcore" } };
11387
+ } catch (err) {
11388
+ return { status: "error", stamped_revision: null, error: errMsg(err) };
11389
+ }
11390
+ },
11391
+ async status(args) {
11392
+ try {
11393
+ const dsn = await buildDsn4(args);
11394
+ const r = await statusEfcore({ projectDir: args.projectDir, dsn });
11395
+ return {
11396
+ applied_version: r.current ?? null,
11397
+ pending: r.pending,
11398
+ applied: [],
11399
+ status: "ok",
11400
+ tool_specific: { tool: r.tool }
11401
+ };
11402
+ } catch (err) {
11403
+ return { applied_version: null, pending: [], applied: [], status: "error", error: errMsg(err) };
11404
+ }
11405
+ },
11406
+ async list(args) {
11407
+ return { files: listEfCoreFiles(args.projectDir) };
11408
+ },
11409
+ // baseline: use stamp (EF has no separate baseline concept).
11410
+ async newMigration(args) {
11411
+ try {
11412
+ const created = await createEfcoreMigration({ projectDir: args.projectDir, slug: args.slug });
11413
+ return {
11414
+ status: "ok",
11415
+ version: efVersion(created.id),
11416
+ filename: path15.basename(created.path),
11417
+ path: created.path
11418
+ };
11419
+ } catch (err) {
11420
+ return { status: "error", version: "", filename: "", path: "", error: errMsg(err) };
11421
+ }
11422
+ }
11423
+ };
11424
+ registerSchemaMigrationAdapter(EfCoreAdapter);
11425
+
11007
11426
  // scripts/lakebase/schema-migrate.ts
11008
11427
  var SchemaMigrationError = class extends Error {
11009
11428
  constructor(message, cause) {
@@ -11013,8 +11432,11 @@ var SchemaMigrationError = class extends Error {
11013
11432
  }
11014
11433
  cause;
11015
11434
  };
11016
- function toolForLanguage(language) {
11435
+ function toolForLanguage(language, projectDir) {
11017
11436
  switch (language) {
11437
+ case "dotnet":
11438
+ if (projectDir && isDotnetFlywayProject(projectDir)) return "flyway";
11439
+ return "efcore";
11018
11440
  case "java":
11019
11441
  case "kotlin":
11020
11442
  return "flyway";
@@ -11025,7 +11447,7 @@ function toolForLanguage(language) {
11025
11447
  }
11026
11448
  }
11027
11449
  function adapterFor(projectDir, language) {
11028
- const override = language ? toolForLanguage(language) : void 0;
11450
+ const override = language ? toolForLanguage(language, projectDir) : void 0;
11029
11451
  return resolveSchemaMigrationAdapter(projectDir, override);
11030
11452
  }
11031
11453
  var TierMigrationRefusedError = class extends Error {
@@ -11283,7 +11705,7 @@ async function runScmMergeCli(argv) {
11283
11705
  `);
11284
11706
  return 0;
11285
11707
  }
11286
- const projectDir = path14.resolve(args.projectDir ?? process.cwd());
11708
+ const projectDir = path17.resolve(args.projectDir ?? process.cwd());
11287
11709
  const waitMigrate = args.noWaitMigrate ? false : true;
11288
11710
  const verifyMigrateAuth = waitMigrate && !args.noVerifyMigrateAuth ? async () => {
11289
11711
  try {