nexusql 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -14
- package/dist/cli.js +52 -16
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +47 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -186,6 +186,7 @@ interface MigraResult {
|
|
|
186
186
|
*/
|
|
187
187
|
declare function runMigra(fromUrl: string, toUrl: string, options?: {
|
|
188
188
|
unsafe?: boolean;
|
|
189
|
+
schemas?: string[];
|
|
189
190
|
}): MigraResult;
|
|
190
191
|
/**
|
|
191
192
|
* Filter out schema_migrations table from migration SQL.
|
|
@@ -193,10 +194,13 @@ declare function runMigra(fromUrl: string, toUrl: string, options?: {
|
|
|
193
194
|
declare function filterSchemaMigrations(sql: string): string;
|
|
194
195
|
|
|
195
196
|
interface NexusqlConfig {
|
|
196
|
-
|
|
197
|
+
dbmlFile: string;
|
|
198
|
+
/** @deprecated Use dbmlFile instead */
|
|
199
|
+
schema?: string;
|
|
197
200
|
migrations: string;
|
|
198
201
|
extensions: string[];
|
|
199
202
|
databaseUrl?: string;
|
|
203
|
+
targetDbSchemas?: string[];
|
|
200
204
|
}
|
|
201
205
|
/**
|
|
202
206
|
* Load configuration from nexusql.config.js or defaults.
|
package/dist/index.js
CHANGED
|
@@ -1793,6 +1793,12 @@ var Database = class _Database {
|
|
|
1793
1793
|
* Drop a database if it exists.
|
|
1794
1794
|
*/
|
|
1795
1795
|
async dropDatabase(name) {
|
|
1796
|
+
await this.exec(`
|
|
1797
|
+
SELECT pg_terminate_backend(pg_stat_activity.pid)
|
|
1798
|
+
FROM pg_stat_activity
|
|
1799
|
+
WHERE pg_stat_activity.datname = '${name}'
|
|
1800
|
+
AND pid <> pg_backend_pid();
|
|
1801
|
+
`);
|
|
1796
1802
|
await this.exec(`DROP DATABASE IF EXISTS "${name}";`);
|
|
1797
1803
|
}
|
|
1798
1804
|
/**
|
|
@@ -2109,6 +2115,11 @@ function runMigra(fromUrl, toUrl, options = {}) {
|
|
|
2109
2115
|
if (options.unsafe) {
|
|
2110
2116
|
args.push("--unsafe");
|
|
2111
2117
|
}
|
|
2118
|
+
if (options.schemas?.length) {
|
|
2119
|
+
for (const schema of options.schemas) {
|
|
2120
|
+
args.push("--schema", schema);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2112
2123
|
try {
|
|
2113
2124
|
const output = execFileSync("migra", args, {
|
|
2114
2125
|
encoding: "utf-8",
|
|
@@ -2136,9 +2147,10 @@ import { join as join2 } from "path";
|
|
|
2136
2147
|
import { pathToFileURL } from "url";
|
|
2137
2148
|
import { config as loadDotenv } from "dotenv";
|
|
2138
2149
|
var DEFAULT_CONFIG = {
|
|
2139
|
-
|
|
2150
|
+
dbmlFile: "./schema.dbml",
|
|
2140
2151
|
migrations: "./db/migrations",
|
|
2141
|
-
extensions: ["uuid-ossp"]
|
|
2152
|
+
extensions: ["uuid-ossp"],
|
|
2153
|
+
targetDbSchemas: ["public"]
|
|
2142
2154
|
};
|
|
2143
2155
|
async function loadConfig(cwd = process.cwd()) {
|
|
2144
2156
|
loadDotenv();
|
|
@@ -2152,30 +2164,42 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
2152
2164
|
} catch {
|
|
2153
2165
|
}
|
|
2154
2166
|
}
|
|
2155
|
-
|
|
2167
|
+
const finalConfig = {
|
|
2156
2168
|
...DEFAULT_CONFIG,
|
|
2157
2169
|
...userConfig,
|
|
2158
2170
|
databaseUrl: process.env.DATABASE_URL || userConfig.databaseUrl
|
|
2159
2171
|
};
|
|
2172
|
+
if (userConfig.schema && !userConfig.dbmlFile) {
|
|
2173
|
+
console.warn(
|
|
2174
|
+
"Warning: 'schema' config option is deprecated. Use 'dbmlFile' instead."
|
|
2175
|
+
);
|
|
2176
|
+
finalConfig.dbmlFile = userConfig.schema;
|
|
2177
|
+
}
|
|
2178
|
+
return finalConfig;
|
|
2160
2179
|
}
|
|
2161
2180
|
function getDatabaseUrl(config) {
|
|
2162
2181
|
const url = config.databaseUrl || process.env.DATABASE_URL;
|
|
2163
2182
|
if (!url) {
|
|
2164
|
-
throw new Error(
|
|
2183
|
+
throw new Error(
|
|
2184
|
+
"DATABASE_URL not set. Set it in .env or nexusql.config.js"
|
|
2185
|
+
);
|
|
2165
2186
|
}
|
|
2166
2187
|
return url;
|
|
2167
2188
|
}
|
|
2168
2189
|
function generateConfigTemplate() {
|
|
2169
2190
|
return `/** @type {import('nexusql').NexusqlConfig} */
|
|
2170
|
-
|
|
2191
|
+
module.exports = {
|
|
2171
2192
|
// Path to your DBML schema file
|
|
2172
|
-
|
|
2193
|
+
dbmlFile: './schema.dbml',
|
|
2173
2194
|
|
|
2174
2195
|
// Directory for migration files
|
|
2175
2196
|
migrations: './db/migrations',
|
|
2176
2197
|
|
|
2177
2198
|
// PostgreSQL extensions to install in temp database
|
|
2178
2199
|
extensions: ['uuid-ossp'],
|
|
2200
|
+
|
|
2201
|
+
// Restrict to specific PostgreSQL schemas (optional, default: ['public'])
|
|
2202
|
+
// targetDbSchemas: ['public'],
|
|
2179
2203
|
};
|
|
2180
2204
|
`;
|
|
2181
2205
|
}
|
|
@@ -3563,7 +3587,7 @@ async function gen(options = {}) {
|
|
|
3563
3587
|
const db = new Database(databaseUrl);
|
|
3564
3588
|
const spinner = ora();
|
|
3565
3589
|
spinner.start("Reading DBML schema...");
|
|
3566
|
-
const schemaPath = resolve(config.
|
|
3590
|
+
const schemaPath = resolve(config.dbmlFile);
|
|
3567
3591
|
let dbmlContent;
|
|
3568
3592
|
try {
|
|
3569
3593
|
dbmlContent = readFileSync2(schemaPath, "utf-8");
|
|
@@ -3599,10 +3623,17 @@ async function gen(options = {}) {
|
|
|
3599
3623
|
Tables in temp database: ${tables.join(", ")}`));
|
|
3600
3624
|
}
|
|
3601
3625
|
spinner.start("Generating migration diff...");
|
|
3626
|
+
const targetDbSchemas = config.targetDbSchemas;
|
|
3627
|
+
if (targetDbSchemas?.length) {
|
|
3628
|
+
console.log(
|
|
3629
|
+
source_default.dim(`
|
|
3630
|
+
Restricting to schemas: ${targetDbSchemas.join(", ")}`)
|
|
3631
|
+
);
|
|
3632
|
+
}
|
|
3602
3633
|
const migraResult = runMigra(
|
|
3603
3634
|
db.getConnectionUrl(),
|
|
3604
3635
|
tempDb.getConnectionUrl(),
|
|
3605
|
-
{ unsafe: true }
|
|
3636
|
+
{ unsafe: true, schemas: targetDbSchemas }
|
|
3606
3637
|
);
|
|
3607
3638
|
migrationSql = filterSchemaMigrations(migraResult.sql);
|
|
3608
3639
|
if (migraResult.hasChanges) {
|
|
@@ -3611,7 +3642,8 @@ Tables in temp database: ${tables.join(", ")}`));
|
|
|
3611
3642
|
spinner.info("No schema changes detected");
|
|
3612
3643
|
}
|
|
3613
3644
|
spinner.start("Checking comment changes...");
|
|
3614
|
-
|
|
3645
|
+
spinner.start("Checking comment changes...");
|
|
3646
|
+
const commentSql = await getCommentChanges(db, tempDb, targetDbSchemas);
|
|
3615
3647
|
if (commentSql) {
|
|
3616
3648
|
migrationSql = migrationSql ? `${migrationSql}
|
|
3617
3649
|
|
|
@@ -3625,8 +3657,8 @@ ${commentSql}`;
|
|
|
3625
3657
|
try {
|
|
3626
3658
|
await db.dropDatabase(tempDbName);
|
|
3627
3659
|
spinner.succeed("Cleaned up temp database");
|
|
3628
|
-
} catch {
|
|
3629
|
-
spinner.warn(
|
|
3660
|
+
} catch (error) {
|
|
3661
|
+
spinner.warn(`Failed to cleanup temp database: ${error}`);
|
|
3630
3662
|
}
|
|
3631
3663
|
}
|
|
3632
3664
|
const finalSql = migrationSql || "-- No changes detected";
|
|
@@ -3640,7 +3672,8 @@ Migration SQL written to: ${options.output}`));
|
|
|
3640
3672
|
}
|
|
3641
3673
|
return finalSql;
|
|
3642
3674
|
}
|
|
3643
|
-
async function getCommentChanges(currentDb, targetDb) {
|
|
3675
|
+
async function getCommentChanges(currentDb, targetDb, schemas) {
|
|
3676
|
+
const schemaFilter = schemas && schemas.length > 0 ? `AND c.table_schema IN (${schemas.map((s) => `'${s}'`).join(", ")})` : "";
|
|
3644
3677
|
const commentQuery = `
|
|
3645
3678
|
SELECT
|
|
3646
3679
|
format('COMMENT ON COLUMN %I.%I IS %L;',
|
|
@@ -3655,8 +3688,8 @@ async function getCommentChanges(currentDb, targetDb) {
|
|
|
3655
3688
|
JOIN pg_catalog.pg_class pc ON pc.relname = c.table_name
|
|
3656
3689
|
JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace AND pn.nspname = c.table_schema
|
|
3657
3690
|
LEFT JOIN pg_catalog.pg_description pgd ON pgd.objoid = pc.oid AND pgd.objsubid = c.ordinal_position
|
|
3658
|
-
WHERE c.
|
|
3659
|
-
|
|
3691
|
+
WHERE c.table_name != 'schema_migrations'
|
|
3692
|
+
${schemaFilter}
|
|
3660
3693
|
ORDER BY c.table_name, c.ordinal_position;
|
|
3661
3694
|
`;
|
|
3662
3695
|
const [currentComments, targetComments] = await Promise.all([
|