@plyaz/db 0.1.1 → 0.3.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/dist/adapters/sql/SQLAdapter.d.ts +1 -0
- package/dist/adapters/sql/SQLAdapter.d.ts.map +1 -1
- package/dist/cli/index.js +862 -51
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +321 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +321 -18
- package/dist/index.mjs.map +1 -1
- package/dist/migrations/MigrationManager.d.ts +22 -0
- package/dist/migrations/MigrationManager.d.ts.map +1 -1
- package/dist/repository/BaseRepository.d.ts +9 -0
- package/dist/repository/BaseRepository.d.ts.map +1 -1
- package/dist/seeds/SeedManager.d.ts +25 -1
- package/dist/seeds/SeedManager.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -3597,6 +3597,7 @@ var SupabaseAdapter = class {
|
|
|
3597
3597
|
return ops[operator]();
|
|
3598
3598
|
}
|
|
3599
3599
|
};
|
|
3600
|
+
var SQL_ERROR_TRUNCATE_LENGTH = 500;
|
|
3600
3601
|
var SQLAdapter = class {
|
|
3601
3602
|
static {
|
|
3602
3603
|
__name(this, "SQLAdapter");
|
|
@@ -3607,6 +3608,7 @@ var SQLAdapter = class {
|
|
|
3607
3608
|
idColumnMap = /* @__PURE__ */ new Map();
|
|
3608
3609
|
configIdColumns;
|
|
3609
3610
|
defaultSchema;
|
|
3611
|
+
showSqlInErrors;
|
|
3610
3612
|
/**
|
|
3611
3613
|
* Creates a new SQLAdapter instance.
|
|
3612
3614
|
* @param {SQLAdapterConfig} config - Configuration for the SQL adapter.
|
|
@@ -3620,6 +3622,7 @@ var SQLAdapter = class {
|
|
|
3620
3622
|
constructor(config) {
|
|
3621
3623
|
this.config = config;
|
|
3622
3624
|
this.defaultSchema = config.schema ?? "public";
|
|
3625
|
+
this.showSqlInErrors = config.showSqlInErrors ?? true;
|
|
3623
3626
|
this.pool = new Pool({
|
|
3624
3627
|
connectionString: config.connectionString,
|
|
3625
3628
|
...config.pool
|
|
@@ -3738,16 +3741,16 @@ var SQLAdapter = class {
|
|
|
3738
3741
|
const result = await this.pool.query(sql2, params);
|
|
3739
3742
|
return result.rows;
|
|
3740
3743
|
} catch (error) {
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
);
|
|
3744
|
+
const truncatedSql = sql2.slice(0, SQL_ERROR_TRUNCATE_LENGTH);
|
|
3745
|
+
const sqlSuffix = sql2.length > SQL_ERROR_TRUNCATE_LENGTH ? "..." : "";
|
|
3746
|
+
const errorMessage = this.showSqlInErrors ? `SQL Error: ${error.message}
|
|
3747
|
+
Query: ${truncatedSql}${sqlSuffix}` : `SQL Error: ${error.message}`;
|
|
3748
|
+
throw new DatabaseError(errorMessage, DATABASE_ERROR_CODES.QUERY_FAILED, {
|
|
3749
|
+
context: {
|
|
3750
|
+
source: "SQLAdapter.query"
|
|
3751
|
+
},
|
|
3752
|
+
cause: error
|
|
3753
|
+
});
|
|
3751
3754
|
}
|
|
3752
3755
|
}
|
|
3753
3756
|
/**
|
|
@@ -7188,6 +7191,17 @@ var BaseRepository = class {
|
|
|
7188
7191
|
__name(this, "BaseRepository");
|
|
7189
7192
|
}
|
|
7190
7193
|
defaultConfig;
|
|
7194
|
+
/**
|
|
7195
|
+
* Get the table name for this repository
|
|
7196
|
+
*
|
|
7197
|
+
* Useful for transaction operations where you need the table name
|
|
7198
|
+
* to execute raw queries within a transaction context.
|
|
7199
|
+
*
|
|
7200
|
+
* @returns The table name this repository operates on
|
|
7201
|
+
*/
|
|
7202
|
+
getTableName() {
|
|
7203
|
+
return this.tableName;
|
|
7204
|
+
}
|
|
7191
7205
|
/**
|
|
7192
7206
|
* Merges default repository config with per-operation config
|
|
7193
7207
|
* Per-operation config takes precedence over default config
|
|
@@ -10418,6 +10432,10 @@ __name(DataValidationPipe, "DataValidationPipe");
|
|
|
10418
10432
|
DataValidationPipe = __decorateClass([
|
|
10419
10433
|
Injectable()
|
|
10420
10434
|
], DataValidationPipe);
|
|
10435
|
+
var DESCRIPTION_MAX_LENGTH = 60;
|
|
10436
|
+
var FALLBACK_DESCRIPTION_LENGTH = 50;
|
|
10437
|
+
var PROGRESS_LOG_INTERVAL = 10;
|
|
10438
|
+
var ERROR_MESSAGE_MAX_LENGTH = 300;
|
|
10421
10439
|
var MigrationManager = class {
|
|
10422
10440
|
static {
|
|
10423
10441
|
__name(this, "MigrationManager");
|
|
@@ -10527,6 +10545,122 @@ var MigrationManager = class {
|
|
|
10527
10545
|
}
|
|
10528
10546
|
return { upSQL: sql2.trim(), downSQL: null };
|
|
10529
10547
|
}
|
|
10548
|
+
/**
|
|
10549
|
+
* Process dollar-quoted string delimiters ($$ or $tag$)
|
|
10550
|
+
* Returns updated state for tracking if we're inside a dollar block
|
|
10551
|
+
*/
|
|
10552
|
+
processDollarDelimiters(line, inDollarBlock, dollarTag) {
|
|
10553
|
+
const dollarMatch = line.match(/\$([a-zA-Z_]*)\$/g);
|
|
10554
|
+
if (!dollarMatch) return { inDollarBlock, dollarTag };
|
|
10555
|
+
let currentInBlock = inDollarBlock;
|
|
10556
|
+
let currentTag = dollarTag;
|
|
10557
|
+
for (const match of dollarMatch) {
|
|
10558
|
+
if (!currentInBlock) {
|
|
10559
|
+
currentInBlock = true;
|
|
10560
|
+
currentTag = match;
|
|
10561
|
+
} else if (match === currentTag) {
|
|
10562
|
+
currentInBlock = false;
|
|
10563
|
+
currentTag = "";
|
|
10564
|
+
}
|
|
10565
|
+
}
|
|
10566
|
+
return { inDollarBlock: currentInBlock, dollarTag: currentTag };
|
|
10567
|
+
}
|
|
10568
|
+
/**
|
|
10569
|
+
* Filter out comment-only statements
|
|
10570
|
+
*/
|
|
10571
|
+
isNonCommentStatement(statement) {
|
|
10572
|
+
const withoutComments = statement.replace(/--.*$/gm, "").trim();
|
|
10573
|
+
return withoutComments.length > 0;
|
|
10574
|
+
}
|
|
10575
|
+
/**
|
|
10576
|
+
* Split SQL into individual statements for better error reporting
|
|
10577
|
+
* Handles $$ delimited blocks (functions, triggers) correctly
|
|
10578
|
+
*/
|
|
10579
|
+
splitSqlStatements(sql2) {
|
|
10580
|
+
const statements = [];
|
|
10581
|
+
let current = "";
|
|
10582
|
+
let inDollarBlock = false;
|
|
10583
|
+
let dollarTag = "";
|
|
10584
|
+
for (const line of sql2.split("\n")) {
|
|
10585
|
+
const trimmedLine = line.trim();
|
|
10586
|
+
const isEmptyOrComment = trimmedLine === "" || trimmedLine.startsWith("--");
|
|
10587
|
+
current += line + "\n";
|
|
10588
|
+
if (isEmptyOrComment) continue;
|
|
10589
|
+
const dollarState = this.processDollarDelimiters(
|
|
10590
|
+
line,
|
|
10591
|
+
inDollarBlock,
|
|
10592
|
+
dollarTag
|
|
10593
|
+
);
|
|
10594
|
+
inDollarBlock = dollarState.inDollarBlock;
|
|
10595
|
+
dollarTag = dollarState.dollarTag;
|
|
10596
|
+
const isEndOfStatement = !inDollarBlock && trimmedLine.endsWith(";");
|
|
10597
|
+
if (isEndOfStatement && current.trim()) {
|
|
10598
|
+
statements.push(current.trim());
|
|
10599
|
+
current = "";
|
|
10600
|
+
}
|
|
10601
|
+
}
|
|
10602
|
+
if (current.trim()) {
|
|
10603
|
+
statements.push(current.trim());
|
|
10604
|
+
}
|
|
10605
|
+
return statements.filter((s) => this.isNonCommentStatement(s));
|
|
10606
|
+
}
|
|
10607
|
+
/**
|
|
10608
|
+
* Extract a short description from a SQL statement for logging
|
|
10609
|
+
*/
|
|
10610
|
+
getStatementDescription(statement) {
|
|
10611
|
+
const firstLine = statement.split("\n").find((l) => l.trim() && !l.trim().startsWith("--"))?.trim() ?? "";
|
|
10612
|
+
const patterns = [
|
|
10613
|
+
/^(CREATE\s+(?:OR\s+REPLACE\s+)?(?:TABLE|INDEX|UNIQUE\s+INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s(]+)/i,
|
|
10614
|
+
/^(ALTER\s+TABLE)\s+([^\s]+)/i,
|
|
10615
|
+
/^(DROP\s+(?:TABLE|INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+EXISTS\s+)?([^\s(;]+)/i,
|
|
10616
|
+
/^(INSERT\s+INTO)\s+([^\s(]+)/i,
|
|
10617
|
+
/^(COMMENT\s+ON\s+(?:TABLE|COLUMN|INDEX|FUNCTION|TYPE))\s+([^\s]+)/i,
|
|
10618
|
+
/^(GRANT|REVOKE)\s+.+\s+ON\s+([^\s]+)/i
|
|
10619
|
+
];
|
|
10620
|
+
for (const pattern of patterns) {
|
|
10621
|
+
const match = firstLine.match(pattern);
|
|
10622
|
+
if (match) {
|
|
10623
|
+
return `${match[1]} ${match[2]}`.slice(0, DESCRIPTION_MAX_LENGTH);
|
|
10624
|
+
}
|
|
10625
|
+
}
|
|
10626
|
+
const truncated = firstLine.slice(0, FALLBACK_DESCRIPTION_LENGTH);
|
|
10627
|
+
const suffix = firstLine.length > FALLBACK_DESCRIPTION_LENGTH ? "..." : "";
|
|
10628
|
+
return truncated + suffix;
|
|
10629
|
+
}
|
|
10630
|
+
/**
|
|
10631
|
+
* Execute SQL statements individually with better error reporting
|
|
10632
|
+
*/
|
|
10633
|
+
async executeSqlStatements(adapter, sql2, migrationVersion) {
|
|
10634
|
+
const statements = this.splitSqlStatements(sql2);
|
|
10635
|
+
const total = statements.length;
|
|
10636
|
+
console.log(` → ${total} statements to execute`);
|
|
10637
|
+
for (let i = 0; i < statements.length; i++) {
|
|
10638
|
+
const statement = statements[i];
|
|
10639
|
+
const description = this.getStatementDescription(statement);
|
|
10640
|
+
try {
|
|
10641
|
+
await adapter.query(statement);
|
|
10642
|
+
const isInterval = (i + 1) % PROGRESS_LOG_INTERVAL === 0;
|
|
10643
|
+
const isLast = i === total - 1;
|
|
10644
|
+
const isSignificant = Boolean(
|
|
10645
|
+
description.match(/^(CREATE TABLE|CREATE FUNCTION|CREATE TRIGGER)/i)
|
|
10646
|
+
);
|
|
10647
|
+
if (isInterval || isLast || isSignificant) {
|
|
10648
|
+
console.log(` ✓ [${i + 1}/${total}] ${description}`);
|
|
10649
|
+
}
|
|
10650
|
+
} catch (error) {
|
|
10651
|
+
console.log(` ✗ [${i + 1}/${total}] ${description}`);
|
|
10652
|
+
const rawMessage = error.message;
|
|
10653
|
+
const errorMessage = rawMessage.replace(/^SQL Error:\s*/i, "").replace(/^Failed to execute query:.*?-\s*/i, "").slice(0, ERROR_MESSAGE_MAX_LENGTH);
|
|
10654
|
+
throw new DatabaseError(
|
|
10655
|
+
`Migration ${migrationVersion} failed at statement ${i + 1}/${total}:
|
|
10656
|
+
Statement: ${description}
|
|
10657
|
+
Error: ${errorMessage}`,
|
|
10658
|
+
DATABASE_ERROR_CODES.QUERY_FAILED,
|
|
10659
|
+
{ cause: error }
|
|
10660
|
+
);
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
}
|
|
10530
10664
|
/**
|
|
10531
10665
|
* Load SQL migration from file
|
|
10532
10666
|
*/
|
|
@@ -10538,12 +10672,20 @@ var MigrationManager = class {
|
|
|
10538
10672
|
name: migrationFile.name,
|
|
10539
10673
|
up: /* @__PURE__ */ __name(async (adapter) => {
|
|
10540
10674
|
if (typeof adapter.query === "function") {
|
|
10541
|
-
await
|
|
10675
|
+
await this.executeSqlStatements(
|
|
10676
|
+
adapter,
|
|
10677
|
+
upSQL,
|
|
10678
|
+
migrationFile.version
|
|
10679
|
+
);
|
|
10542
10680
|
}
|
|
10543
10681
|
}, "up"),
|
|
10544
10682
|
down: /* @__PURE__ */ __name(async (adapter) => {
|
|
10545
10683
|
if (downSQL && typeof adapter.query === "function") {
|
|
10546
|
-
await
|
|
10684
|
+
await this.executeSqlStatements(
|
|
10685
|
+
adapter,
|
|
10686
|
+
downSQL,
|
|
10687
|
+
migrationFile.version
|
|
10688
|
+
);
|
|
10547
10689
|
} else {
|
|
10548
10690
|
console.warn(
|
|
10549
10691
|
`[Migrations] No DOWN migration for ${migrationFile.version}`
|
|
@@ -10650,6 +10792,7 @@ var MigrationManager = class {
|
|
|
10650
10792
|
/**
|
|
10651
10793
|
* Run all pending migrations
|
|
10652
10794
|
*/
|
|
10795
|
+
/* eslint-disable max-depth, complexity */
|
|
10653
10796
|
async up(targetVersion) {
|
|
10654
10797
|
try {
|
|
10655
10798
|
await this.initialize();
|
|
@@ -10670,9 +10813,15 @@ var MigrationManager = class {
|
|
|
10670
10813
|
const migration = await this.loadMigration(migrationFile);
|
|
10671
10814
|
const startTime = Date.now();
|
|
10672
10815
|
if (typeof this.adapter.transaction === "function") {
|
|
10673
|
-
await this.adapter.transaction(async () => {
|
|
10816
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10674
10817
|
await migration.up(this.adapter);
|
|
10675
10818
|
});
|
|
10819
|
+
if (!txResult.success) {
|
|
10820
|
+
throw txResult.error ?? new DatabaseError(
|
|
10821
|
+
`Migration ${migration.version} failed`,
|
|
10822
|
+
DATABASE_ERROR_CODES.QUERY_FAILED
|
|
10823
|
+
);
|
|
10824
|
+
}
|
|
10676
10825
|
} else {
|
|
10677
10826
|
await migration.up(this.adapter);
|
|
10678
10827
|
}
|
|
@@ -10727,9 +10876,15 @@ var MigrationManager = class {
|
|
|
10727
10876
|
const migration = await this.loadMigration(migrationFile);
|
|
10728
10877
|
const startTime = Date.now();
|
|
10729
10878
|
if (typeof this.adapter.transaction === "function") {
|
|
10730
|
-
await this.adapter.transaction(async () => {
|
|
10879
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10731
10880
|
await migration.down(this.adapter);
|
|
10732
10881
|
});
|
|
10882
|
+
if (!txResult.success) {
|
|
10883
|
+
throw txResult.error ?? new DatabaseError(
|
|
10884
|
+
`Rollback ${appliedMigration.version} failed`,
|
|
10885
|
+
DATABASE_ERROR_CODES.QUERY_FAILED
|
|
10886
|
+
);
|
|
10887
|
+
}
|
|
10733
10888
|
} else {
|
|
10734
10889
|
await migration.down(this.adapter);
|
|
10735
10890
|
}
|
|
@@ -10788,6 +10943,10 @@ var MigrationManager = class {
|
|
|
10788
10943
|
}
|
|
10789
10944
|
}
|
|
10790
10945
|
};
|
|
10946
|
+
var DESCRIPTION_MAX_LENGTH2 = 60;
|
|
10947
|
+
var FALLBACK_DESCRIPTION_LENGTH2 = 50;
|
|
10948
|
+
var PROGRESS_LOG_INTERVAL2 = 10;
|
|
10949
|
+
var ERROR_MESSAGE_MAX_LENGTH2 = 300;
|
|
10791
10950
|
var SeedManager = class {
|
|
10792
10951
|
static {
|
|
10793
10952
|
__name(this, "SeedManager");
|
|
@@ -10856,7 +11015,7 @@ var SeedManager = class {
|
|
|
10856
11015
|
const files = fs.readdirSync(this.seedsPath);
|
|
10857
11016
|
const seeds = [];
|
|
10858
11017
|
for (const file of files) {
|
|
10859
|
-
const match = file.match(/^(\d+)_(.+)\.(ts|js)$/);
|
|
11018
|
+
const match = file.match(/^(\d+)_(.+)\.(ts|js|sql)$/);
|
|
10860
11019
|
if (match) {
|
|
10861
11020
|
const [, order, name] = match;
|
|
10862
11021
|
seeds.push({
|
|
@@ -10869,9 +11028,141 @@ var SeedManager = class {
|
|
|
10869
11028
|
return seeds.sort((a, b) => a.order - b.order);
|
|
10870
11029
|
}
|
|
10871
11030
|
/**
|
|
10872
|
-
*
|
|
11031
|
+
* Process dollar-quoted string delimiters ($$ or $tag$)
|
|
11032
|
+
*/
|
|
11033
|
+
processDollarDelimiters(line, inDollarBlock, dollarTag) {
|
|
11034
|
+
const dollarMatch = line.match(/\$([a-zA-Z_]*)\$/g);
|
|
11035
|
+
if (!dollarMatch) return { inDollarBlock, dollarTag };
|
|
11036
|
+
let currentInBlock = inDollarBlock;
|
|
11037
|
+
let currentTag = dollarTag;
|
|
11038
|
+
for (const match of dollarMatch) {
|
|
11039
|
+
if (!currentInBlock) {
|
|
11040
|
+
currentInBlock = true;
|
|
11041
|
+
currentTag = match;
|
|
11042
|
+
} else if (match === currentTag) {
|
|
11043
|
+
currentInBlock = false;
|
|
11044
|
+
currentTag = "";
|
|
11045
|
+
}
|
|
11046
|
+
}
|
|
11047
|
+
return { inDollarBlock: currentInBlock, dollarTag: currentTag };
|
|
11048
|
+
}
|
|
11049
|
+
/**
|
|
11050
|
+
* Filter out comment-only statements
|
|
11051
|
+
*/
|
|
11052
|
+
isNonCommentStatement(statement) {
|
|
11053
|
+
const withoutComments = statement.replace(/--.*$/gm, "").trim();
|
|
11054
|
+
return withoutComments.length > 0;
|
|
11055
|
+
}
|
|
11056
|
+
/**
|
|
11057
|
+
* Split SQL into individual statements for better error reporting
|
|
11058
|
+
*/
|
|
11059
|
+
splitSqlStatements(sql2) {
|
|
11060
|
+
const statements = [];
|
|
11061
|
+
let current = "";
|
|
11062
|
+
let inDollarBlock = false;
|
|
11063
|
+
let dollarTag = "";
|
|
11064
|
+
for (const line of sql2.split("\n")) {
|
|
11065
|
+
const trimmedLine = line.trim();
|
|
11066
|
+
const isEmptyOrComment = trimmedLine === "" || trimmedLine.startsWith("--");
|
|
11067
|
+
current += line + "\n";
|
|
11068
|
+
if (isEmptyOrComment) continue;
|
|
11069
|
+
const dollarState = this.processDollarDelimiters(
|
|
11070
|
+
line,
|
|
11071
|
+
inDollarBlock,
|
|
11072
|
+
dollarTag
|
|
11073
|
+
);
|
|
11074
|
+
inDollarBlock = dollarState.inDollarBlock;
|
|
11075
|
+
dollarTag = dollarState.dollarTag;
|
|
11076
|
+
if (!inDollarBlock && trimmedLine.endsWith(";") && current.trim()) {
|
|
11077
|
+
statements.push(current.trim());
|
|
11078
|
+
current = "";
|
|
11079
|
+
}
|
|
11080
|
+
}
|
|
11081
|
+
if (current.trim()) {
|
|
11082
|
+
statements.push(current.trim());
|
|
11083
|
+
}
|
|
11084
|
+
return statements.filter((s) => this.isNonCommentStatement(s));
|
|
11085
|
+
}
|
|
11086
|
+
/**
|
|
11087
|
+
* Extract a short description from a SQL statement for logging
|
|
11088
|
+
*/
|
|
11089
|
+
getStatementDescription(statement) {
|
|
11090
|
+
const firstLine = statement.split("\n").find((l) => l.trim() && !l.trim().startsWith("--"))?.trim() ?? "";
|
|
11091
|
+
const patterns = [
|
|
11092
|
+
/^(CREATE\s+(?:OR\s+REPLACE\s+)?(?:TABLE|INDEX|UNIQUE\s+INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s(]+)/i,
|
|
11093
|
+
/^(ALTER\s+TABLE)\s+([^\s]+)/i,
|
|
11094
|
+
/^(DROP\s+(?:TABLE|INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+EXISTS\s+)?([^\s(;]+)/i,
|
|
11095
|
+
/^(INSERT\s+INTO)\s+([^\s(]+)/i,
|
|
11096
|
+
/^(COMMENT\s+ON\s+(?:TABLE|COLUMN|INDEX|FUNCTION|TYPE))\s+([^\s]+)/i,
|
|
11097
|
+
/^(GRANT|REVOKE)\s+.+\s+ON\s+([^\s]+)/i
|
|
11098
|
+
];
|
|
11099
|
+
for (const pattern of patterns) {
|
|
11100
|
+
const match = firstLine.match(pattern);
|
|
11101
|
+
if (match) {
|
|
11102
|
+
return `${match[1]} ${match[2]}`.slice(0, DESCRIPTION_MAX_LENGTH2);
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
const truncated = firstLine.slice(0, FALLBACK_DESCRIPTION_LENGTH2);
|
|
11106
|
+
const suffix = firstLine.length > FALLBACK_DESCRIPTION_LENGTH2 ? "..." : "";
|
|
11107
|
+
return truncated + suffix;
|
|
11108
|
+
}
|
|
11109
|
+
/**
|
|
11110
|
+
* Execute SQL statements individually with better error reporting
|
|
11111
|
+
*/
|
|
11112
|
+
async executeSqlStatements(sql2, seedName) {
|
|
11113
|
+
const statements = this.splitSqlStatements(sql2);
|
|
11114
|
+
const total = statements.length;
|
|
11115
|
+
console.log(` → ${total} statements to execute`);
|
|
11116
|
+
for (let i = 0; i < statements.length; i++) {
|
|
11117
|
+
const statement = statements[i];
|
|
11118
|
+
const description = this.getStatementDescription(statement);
|
|
11119
|
+
try {
|
|
11120
|
+
await this.adapter.query(statement);
|
|
11121
|
+
const isInterval = (i + 1) % PROGRESS_LOG_INTERVAL2 === 0;
|
|
11122
|
+
const isLast = i === total - 1;
|
|
11123
|
+
const isSignificant = Boolean(description.match(/^(INSERT INTO)/i));
|
|
11124
|
+
if (isInterval || isLast || isSignificant) {
|
|
11125
|
+
console.log(` ✓ [${i + 1}/${total}] ${description}`);
|
|
11126
|
+
}
|
|
11127
|
+
} catch (error) {
|
|
11128
|
+
console.log(` ✗ [${i + 1}/${total}] ${description}`);
|
|
11129
|
+
const rawMessage = error.message;
|
|
11130
|
+
const errorMessage = rawMessage.replace(/^SQL Error:\s*/i, "").replace(/^Failed to execute query:.*?-\s*/i, "").slice(0, ERROR_MESSAGE_MAX_LENGTH2);
|
|
11131
|
+
throw new DatabaseError(
|
|
11132
|
+
`Seed "${seedName}" failed at statement ${i + 1}/${total}:
|
|
11133
|
+
Statement: ${description}
|
|
11134
|
+
Error: ${errorMessage}`,
|
|
11135
|
+
DATABASE_ERROR_CODES.QUERY_FAILED,
|
|
11136
|
+
{ cause: error }
|
|
11137
|
+
);
|
|
11138
|
+
}
|
|
11139
|
+
}
|
|
11140
|
+
}
|
|
11141
|
+
/**
|
|
11142
|
+
* Load SQL seed from file
|
|
10873
11143
|
*/
|
|
11144
|
+
loadSqlSeed(seedFile) {
|
|
11145
|
+
const sql2 = fs.readFileSync(seedFile.filePath, "utf-8");
|
|
11146
|
+
return {
|
|
11147
|
+
name: seedFile.name,
|
|
11148
|
+
run: /* @__PURE__ */ __name(async () => {
|
|
11149
|
+
if (typeof this.adapter.query === "function") {
|
|
11150
|
+
await this.executeSqlStatements(sql2, seedFile.name);
|
|
11151
|
+
}
|
|
11152
|
+
}, "run"),
|
|
11153
|
+
// SQL seeds don't have cleanup by default
|
|
11154
|
+
cleanup: void 0
|
|
11155
|
+
};
|
|
11156
|
+
}
|
|
11157
|
+
/**
|
|
11158
|
+
* Load seed from file (supports .ts, .js, and .sql)
|
|
11159
|
+
*/
|
|
11160
|
+
// eslint-disable-next-line complexity
|
|
10874
11161
|
async loadSeed(seedFile) {
|
|
11162
|
+
const ext = path.extname(seedFile.filePath);
|
|
11163
|
+
if (ext === ".sql") {
|
|
11164
|
+
return this.loadSqlSeed(seedFile);
|
|
11165
|
+
}
|
|
10875
11166
|
const importPath = seedFile.filePath.startsWith("/") ? seedFile.filePath : new URL(`file:///${seedFile.filePath.replace(/\\/g, "/")}`).href;
|
|
10876
11167
|
const seedModule = await import(importPath);
|
|
10877
11168
|
return {
|
|
@@ -10925,9 +11216,15 @@ var SeedManager = class {
|
|
|
10925
11216
|
*/
|
|
10926
11217
|
async executeSeed(seed) {
|
|
10927
11218
|
if (typeof this.adapter.transaction === "function") {
|
|
10928
|
-
await this.adapter.transaction(async () => {
|
|
11219
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10929
11220
|
await seed.run(this.adapter);
|
|
10930
11221
|
});
|
|
11222
|
+
if (!txResult.success) {
|
|
11223
|
+
throw txResult.error ?? new DatabaseError(
|
|
11224
|
+
`Seed ${seed.name} failed`,
|
|
11225
|
+
DATABASE_ERROR_CODES.QUERY_FAILED
|
|
11226
|
+
);
|
|
11227
|
+
}
|
|
10931
11228
|
} else {
|
|
10932
11229
|
await seed.run(this.adapter);
|
|
10933
11230
|
}
|
|
@@ -10984,9 +11281,15 @@ var SeedManager = class {
|
|
|
10984
11281
|
async executeCleanup(seed) {
|
|
10985
11282
|
if (!seed.cleanup) return;
|
|
10986
11283
|
if (typeof this.adapter.transaction === "function") {
|
|
10987
|
-
await this.adapter.transaction(async () => {
|
|
11284
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10988
11285
|
await seed.cleanup(this.adapter);
|
|
10989
11286
|
});
|
|
11287
|
+
if (!txResult.success) {
|
|
11288
|
+
throw txResult.error ?? new DatabaseError(
|
|
11289
|
+
`Seed cleanup for ${seed.name} failed`,
|
|
11290
|
+
DATABASE_ERROR_CODES.QUERY_FAILED
|
|
11291
|
+
);
|
|
11292
|
+
}
|
|
10990
11293
|
} else {
|
|
10991
11294
|
await seed.cleanup(this.adapter);
|
|
10992
11295
|
}
|