Skip to content

Commit 7eb39f0

Browse files
dankochetovAndriiShermanAleksandrShermanSukairo-02RomanNabukhotnyi
authored
Fix drizzle-kit tsconfig path alias resolution (#5417)
* Fix tsconfig path aliases in drizzle-kit * Fix typecheck and import whitelist for tsconfig tests * Improve tsconfig alias resolution * update tests * support node sqlite for kit (#5475) * added node:sqlite support driver to drizzle-kit * fix * updated compatibilityVersion * added node version warn for node:sqlite * bump to beta.18 * added transactions to up-pg * fix * fixed attw * pass dbs to migrate instead of db.sessions + added batch for neon-http in up migrate * fix * changed type: "http" to mode: "transaction" | "execute" * fixed attw + added batch mode * `hanjiv0.0.8` update, removed unused dependency * Fixed type errors * fix: Correct string interpolation for database name in DuckDB introspection queries (#5486) * Build fix, postponed tests * Updated deprecated configs * Reverted kit's tsdown to working version, updated config * Reverted tsdown * Updated configs * Reverted configs * Config fix * Updated tsdown, returned global tsdown, switched build scripts to use bun as was intended * Updated seeder shebang to use bun * Switched to compatible `tsdown` ver * Fixed builder exiting with wrong code * Fixed builder exiting with wrong code * Fixed wrong exit usage * remove as number --------- Co-authored-by: AndriiSherman <andreysherman11@gmail.com> Co-authored-by: Aleksandr Sherman <102579553+AleksandrSherman@users.noreply.github.com> Co-authored-by: Aleksandr Sherman <aleksandrserman@gmail.com> Co-authored-by: Sukairo-02 <sreka9056@gmail.com> Co-authored-by: Roman Nabukhotnyi <97584054+RomanNabukhotnyi@users.noreply.github.com>
1 parent 54ffee4 commit 7eb39f0

46 files changed

Lines changed: 654 additions & 382 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
## New driver support for `kit` and `studio`
2+
3+
You can now use the `node:sqlite` driver to run migrations and browse Drizzle Studio. If `node:sqlite` is available at runtime, we will automatically detect it and use it.
4+
5+
## Fixes
6+
7+
- resolved tsconfig path aliases in drizzle-kit loader using get-tsconfig + jiti alias mapping
8+
- added fixtures and tests covering wildcard and non-wildcard path aliases
9+
- ensured schema load succeeds for alias imports
10+
- Updated to `hanji@0.0.8` - native bun `stringWidth`, `stripANSI` support, errors for non-TTY environments

drizzle-kit/package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "drizzle-kit",
3-
"version": "1.0.0-beta.17",
3+
"version": "1.0.0-beta.18",
44
"homepage": "https://orm.drizzle.team",
55
"keywords": [
66
"drizzle",
@@ -37,7 +37,7 @@
3737
"cli": "tsx ./src/cli/index.ts",
3838
"test": "TEST_CONFIG_PATH_PREFIX=./tests/cli/ vitest run",
3939
"test:types": "pnpm tsc -p ./tsconfig.typetest.json",
40-
"build": "tsx scripts/build.ts",
40+
"build": "bun --bun run scripts/build.ts",
4141
"build:artifact": "pnpm run build",
4242
"build:cli": "rm -rf ./dist && tsx build.cli.ts && cp package.json dist/",
4343
"build:dev": "rm -rf ./dist && tsx build.dev.ts && tsc -p tsconfig.cli-types.json && chmod +x ./dist/index.cjs",
@@ -56,6 +56,7 @@
5656
"@drizzle-team/brocli": "^0.11.0",
5757
"@js-temporal/polyfill": "^0.5.1",
5858
"esbuild": "^0.25.10",
59+
"get-tsconfig": "^4.13.6",
5960
"jiti": "^2.6.1"
6061
},
6162
"devDependencies": {
@@ -99,11 +100,10 @@
99100
"drizzle-orm": "workspace:./drizzle-orm/dist",
100101
"duckdb": "^1.3.2",
101102
"env-paths": "^3.0.0",
102-
"esbuild-register": "^3.6.0",
103103
"gel": "^2.0.0",
104104
"get-port": "^6.1.2",
105105
"glob": "^8.1.0",
106-
"hanji": "^0.0.5",
106+
"hanji": "^0.0.8",
107107
"hono": "^4.7.9",
108108
"json-diff": "1.0.6",
109109
"micromatch": "^4.0.8",
@@ -117,9 +117,7 @@
117117
"pluralize": "^8.0.0",
118118
"postgres": "^3.4.4",
119119
"prettier": "^3.5.3",
120-
"rolldown": "^1.0.0-beta.57",
121120
"semver": "^7.7.2",
122-
"tsdown": "^0.18.3",
123121
"tsx": "^4.20.6",
124122
"typescript": "^5.9.3",
125123
"uuid": "^9.0.1",

drizzle-kit/scripts/build.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async function buildBundle(options: {
5151
dir: 'dist',
5252
format: options.format,
5353
entryFileNames: options.outputName,
54-
inlineDynamicImports: true,
54+
codeSplitting: false,
5555
banner: options.banner,
5656
});
5757

@@ -72,7 +72,7 @@ async function buildCli() {
7272
format: 'cjs',
7373
entryFileNames: 'bin.cjs',
7474
banner: '#!/usr/bin/env node',
75-
inlineDynamicImports: true,
75+
codeSplitting: false,
7676
});
7777

7878
await build.close();
@@ -204,7 +204,7 @@ async function main() {
204204
console.log(`Build completed successfully in ${elapsed}s`);
205205
}
206206

207-
main().catch((e) => {
207+
await main().catch((e) => {
208208
console.error(e);
209209
process.exit(1);
210-
});
210+
}).then(() => process.exit(0));

drizzle-kit/src/cli/commands/studio.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ export type Setup = {
7474
| '@tursodatabase/database'
7575
| 'bun'
7676
| 'duckdb'
77-
| '@duckdb/node-api';
77+
| '@duckdb/node-api'
78+
| 'node:sqlite';
7879
driver?: 'aws-data-api' | 'd1-http' | 'turso' | 'pglite' | 'sqlite-cloud';
7980
databaseName?: string; // for planetscale (driver remove database name from connection string)
8081
proxy: Proxy;

drizzle-kit/src/cli/connections.ts

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,8 @@ export const connectToSQLite = async (
17421742
| 'better-sqlite3'
17431743
| '@sqlitecloud/drivers'
17441744
| '@tursodatabase/database'
1745-
| 'bun';
1745+
| 'bun'
1746+
| 'node:sqlite';
17461747
migrate: (config: string | MigrationConfig) => Promise<void | MigratorInitFailResponse>;
17471748
proxy: Proxy;
17481749
transactionProxy: TransactionProxy;
@@ -2228,8 +2229,87 @@ export const connectToSQLite = async (
22282229
};
22292230
}
22302231

2232+
if (await checkPackage('node:sqlite')) {
2233+
console.log(withStyle.info(`Using 'node:sqlite' driver for database querying`));
2234+
const { DatabaseSync } = await import('node:sqlite');
2235+
const { drizzle } = await import('drizzle-orm/node-sqlite');
2236+
const { migrate } = await import('drizzle-orm/node-sqlite/migrator');
2237+
2238+
const client = new DatabaseSync(credentials.url);
2239+
2240+
const db = drizzle({ client });
2241+
const migrateFn = async (config: MigrationConfig) => {
2242+
return migrate(db, config);
2243+
};
2244+
2245+
const query = async <T>(sql: string, params?: any[]) => {
2246+
const result = client.prepare(sql).all(...(params || []));
2247+
return result as T[];
2248+
};
2249+
const run = async (sql: string) => {
2250+
client.prepare(sql).run();
2251+
};
2252+
2253+
const proxy: Proxy = async (params) => {
2254+
const preparedParams = prepareSqliteParams(params.params || []);
2255+
2256+
const stmt = client.prepare(params.sql);
2257+
if (
2258+
params.method === 'values'
2259+
|| params.method === 'get'
2260+
|| params.method === 'all'
2261+
) {
2262+
stmt.setReturnArrays(params.mode === 'array');
2263+
return stmt.all(...preparedParams);
2264+
}
2265+
2266+
stmt.run(...preparedParams);
2267+
2268+
return [];
2269+
};
2270+
2271+
const transactionProxy: TransactionProxy = async (queries) => {
2272+
const results: (any[] | Error)[] = [];
2273+
2274+
try {
2275+
client.prepare('BEGIN').run();
2276+
2277+
for (const query of queries) {
2278+
const stmt = client.prepare(query.sql);
2279+
if (
2280+
query.method === 'values'
2281+
|| query.method === 'get'
2282+
|| query.method === 'all'
2283+
) {
2284+
const res = stmt.all();
2285+
results.push(res);
2286+
} else {
2287+
stmt.run();
2288+
}
2289+
}
2290+
client.prepare('COMMIT').run();
2291+
} catch (error: any) {
2292+
client.prepare('ROLLBACK').run();
2293+
results.push(error as Error);
2294+
}
2295+
2296+
return results;
2297+
};
2298+
2299+
return {
2300+
packageName: 'node:sqlite',
2301+
query,
2302+
run,
2303+
proxy,
2304+
transactionProxy,
2305+
migrate: migrateFn,
2306+
};
2307+
}
2308+
22312309
console.log(
2232-
"Please install either 'better-sqlite3', 'bun', '@libsql/client' or '@tursodatabase/database' for Drizzle Kit to connect to SQLite databases",
2310+
"Please install either 'better-sqlite3', 'bun', '@libsql/client' or '@tursodatabase/database' for Drizzle Kit to connect to SQLite databases"
2311+
+ '\n'
2312+
+ "To use 'node:sqlite' driver, ensure you're running Node.js v22.5.0 or higher",
22332313
);
22342314
console.warn("For the 'bun' driver, run your script using: bun --bun");
22352315
process.exit(1);

drizzle-kit/src/cli/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const assertEitherPackage = async (
7474
process.exit(1);
7575
};
7676

77-
const requiredApiVersion = 12;
77+
const requiredApiVersion = 13;
7878
export const assertOrmCoreVersion = async () => {
7979
try {
8080
const { compatibilityVersion } = await import('drizzle-orm/version');

drizzle-kit/src/cli/views.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,8 @@ export class MigrateProgress extends TaskView {
17341734
this.on('detach', () => clearInterval(this.timeout));
17351735
}
17361736

1737-
render(status: 'pending' | 'done'): string {
1738-
if (status === 'pending') {
1737+
render(status: 'pending' | 'done' | 'rejected'): string {
1738+
if (status === 'pending' || status === 'rejected') {
17391739
const spin = this.spinner.value();
17401740
return `[${spin}] applying migrations...`;
17411741
}
@@ -1766,8 +1766,8 @@ export class ProgressView extends TaskView {
17661766
this.on('detach', () => clearInterval(this.timeout));
17671767
}
17681768

1769-
render(status: 'pending' | 'done'): string {
1770-
if (status === 'pending') {
1769+
render(status: 'pending' | 'done' | 'rejected'): string {
1770+
if (status === 'pending' || status === 'rejected') {
17711771
const spin = this.spinner.value();
17721772
return `[${spin}] ${this.progressText}\n`;
17731773
}

drizzle-kit/src/dialects/postgres/duckdb-introspect.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const fromDatabase = async (
7171
// SELECT current_setting('default_table_access_method') AS default_am;
7272

7373
const namespacesQuery = db.query<Namespace>(
74-
`SELECT oid, schema_name as name FROM duckdb_schemas() WHERE database_name = ${database} ORDER BY lower(schema_name)`,
74+
`SELECT oid, schema_name as name FROM duckdb_schemas() WHERE database_name = '${database}' ORDER BY lower(schema_name)`,
7575
)
7676
.then((rows) => {
7777
queryCallback('namespaces', rows, null);
@@ -137,7 +137,7 @@ export const fromDatabase = async (
137137
'table' AS "type"
138138
FROM
139139
duckdb_tables()
140-
WHERE database_name = ${database}
140+
WHERE database_name = '${database}'
141141
AND schema_oid IN (${filteredNamespacesIds.join(', ')})
142142
143143
UNION ALL
@@ -150,9 +150,9 @@ export const fromDatabase = async (
150150
'view' AS "type"
151151
FROM
152152
duckdb_views()
153-
WHERE database_name = ${database}
153+
WHERE database_name = '${database}'
154154
AND schema_oid IN (${filteredNamespacesIds.join(', ')})
155-
ORDER BY lower(schema_name), lower(name)
155+
ORDER BY schema_name, name
156156
`).then((rows) => {
157157
queryCallback('tables', rows, null);
158158
return rows;
@@ -328,7 +328,7 @@ export const fromDatabase = async (
328328
referenced_column_names AS "columnsToNames"
329329
FROM
330330
duckdb_constraints()
331-
WHERE database_name = ${database}
331+
WHERE database_name = '${database}'
332332
AND ${filterByTableIds ? `table_oid in ${filterByTableIds}` : 'false'}
333333
ORDER BY constraint_type, lower(constraint_name);
334334
`).then((rows) => {
@@ -360,7 +360,7 @@ export const fromDatabase = async (
360360
duckdb_columns()
361361
WHERE
362362
${filterByTableAndViewIds ? ` table_oid in ${filterByTableAndViewIds}` : 'false'}
363-
AND database_name = ${database}
363+
AND database_name = '${database}'
364364
ORDER BY column_index;
365365
`).then((rows) => {
366366
queryCallback('columns', rows, null);

drizzle-kit/src/utils/utils-node.ts

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import chalk from 'chalk';
22
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync } from 'fs';
3+
import { getTsconfig } from 'get-tsconfig';
34
import { sync as globSync } from 'glob';
4-
import { join, resolve } from 'path';
5+
import { dirname, join, resolve } from 'path';
56
import { snapshotValidator as mysqlSnapshotValidator } from 'src/dialects/mysql/snapshot';
67
import { snapshotValidator as singlestoreSnapshotValidator } from 'src/dialects/singlestore/snapshot';
78
import { parse, pathToFileURL } from 'url';
@@ -134,6 +135,62 @@ export const prepareOutFolder = (out: string) => {
134135
return { snapshots };
135136
};
136137

138+
const tsconfigAliasCache = new Map<string, Record<string, string> | undefined>();
139+
140+
const getAliasesForTsconfig = (baseDir: string): Record<string, string> | undefined => {
141+
const cached = tsconfigAliasCache.get(baseDir);
142+
if (cached !== undefined || tsconfigAliasCache.has(baseDir)) {
143+
return cached;
144+
}
145+
146+
const tsconfig = getTsconfig(baseDir);
147+
const tsconfigPaths = tsconfig?.config?.compilerOptions?.paths as Record<string, string[]> | undefined;
148+
if (!tsconfigPaths || !tsconfig?.path) {
149+
tsconfigAliasCache.set(baseDir, undefined);
150+
return undefined;
151+
}
152+
153+
const tsconfigBaseUrl = tsconfig.config.compilerOptions?.baseUrl ?? '.';
154+
const tsconfigDir = dirname(tsconfig.path);
155+
156+
const aliases = Object.fromEntries(
157+
Object.entries(tsconfigPaths).flatMap(([key, values]) => {
158+
const targets = (values ?? []).filter((value): value is string => Boolean(value));
159+
if (targets.length === 0) return [];
160+
161+
const hasWildcard = key.includes('*') || targets.some((target) => target.includes('*'));
162+
const supportsTrailingWildcard = key.endsWith('/*') && targets.every((target) => target.endsWith('/*'));
163+
if (hasWildcard && !supportsTrailingWildcard) {
164+
console.warn(
165+
chalk.yellow(
166+
`[drizzle-kit] Unsupported tsconfig "paths" mapping "${key}": [${
167+
targets
168+
.map((target) => `"${target}"`)
169+
.join(', ')
170+
}]. Only trailing "/*" patterns are supported; this mapping will be ignored.`,
171+
),
172+
);
173+
return [];
174+
}
175+
176+
const aliasKey = key.endsWith('/*') ? key.slice(0, -1) : key;
177+
const resolvedTargets = targets.map((target) => {
178+
if (supportsTrailingWildcard) {
179+
const targetPrefix = target.slice(0, -1);
180+
return resolve(tsconfigDir, tsconfigBaseUrl, targetPrefix);
181+
}
182+
return resolve(tsconfigDir, tsconfigBaseUrl, target);
183+
});
184+
185+
const selectedTarget = resolvedTargets.find((candidate) => existsSync(candidate)) ?? resolvedTargets[0]!;
186+
return [[aliasKey, selectedTarget]];
187+
}),
188+
);
189+
190+
tsconfigAliasCache.set(baseDir, aliases);
191+
return aliases;
192+
};
193+
137194
/**
138195
* Reads all snapshot files and returns the IDs of leaf nodes (nodes that are
139196
* not referenced as a parent by any other node). When generating a new migration,
@@ -419,13 +476,16 @@ export const loadModule = async <T = unknown>(
419476
const isTS = ext === '.ts' || ext === '.mts' || ext === '.cts';
420477

421478
if (isTS) {
422-
const jiti = require('jiti')(path.dirname(absoluteModulePath), {
479+
const baseDir = path.dirname(absoluteModulePath);
480+
const aliases = getAliasesForTsconfig(baseDir);
481+
// oxlint-disable-next-line consistent-type-imports
482+
const { createJiti } = require('jiti') as typeof import('jiti');
483+
const jiti = createJiti(baseDir, {
423484
interopDefault: true,
424-
esmResolve: true,
485+
alias: aliases,
425486
requireCache: false,
426487
});
427-
const mod = await jiti.import(absoluteModulePath);
428-
return mod;
488+
return jiti.import(absoluteModulePath);
429489
}
430490

431491
const fileUrl = pathToFileURL(absoluteModulePath).href;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { defineConfig } from '../../../src';
2+
3+
export default defineConfig({
4+
schema: './entry.ts',
5+
dialect: 'postgresql',
6+
dbCredentials: {
7+
url: 'postgresql://postgres:postgres@127.0.0.1:5432/db',
8+
},
9+
});

0 commit comments

Comments
 (0)