@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.cjs
CHANGED
|
@@ -3621,6 +3621,7 @@ var SupabaseAdapter = class {
|
|
|
3621
3621
|
return ops[operator]();
|
|
3622
3622
|
}
|
|
3623
3623
|
};
|
|
3624
|
+
var SQL_ERROR_TRUNCATE_LENGTH = 500;
|
|
3624
3625
|
var SQLAdapter = class {
|
|
3625
3626
|
static {
|
|
3626
3627
|
__name(this, "SQLAdapter");
|
|
@@ -3631,6 +3632,7 @@ var SQLAdapter = class {
|
|
|
3631
3632
|
idColumnMap = /* @__PURE__ */ new Map();
|
|
3632
3633
|
configIdColumns;
|
|
3633
3634
|
defaultSchema;
|
|
3635
|
+
showSqlInErrors;
|
|
3634
3636
|
/**
|
|
3635
3637
|
* Creates a new SQLAdapter instance.
|
|
3636
3638
|
* @param {SQLAdapterConfig} config - Configuration for the SQL adapter.
|
|
@@ -3644,6 +3646,7 @@ var SQLAdapter = class {
|
|
|
3644
3646
|
constructor(config) {
|
|
3645
3647
|
this.config = config;
|
|
3646
3648
|
this.defaultSchema = config.schema ?? "public";
|
|
3649
|
+
this.showSqlInErrors = config.showSqlInErrors ?? true;
|
|
3647
3650
|
this.pool = new pg.Pool({
|
|
3648
3651
|
connectionString: config.connectionString,
|
|
3649
3652
|
...config.pool
|
|
@@ -3762,16 +3765,16 @@ var SQLAdapter = class {
|
|
|
3762
3765
|
const result = await this.pool.query(sql2, params);
|
|
3763
3766
|
return result.rows;
|
|
3764
3767
|
} catch (error) {
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
);
|
|
3768
|
+
const truncatedSql = sql2.slice(0, SQL_ERROR_TRUNCATE_LENGTH);
|
|
3769
|
+
const sqlSuffix = sql2.length > SQL_ERROR_TRUNCATE_LENGTH ? "..." : "";
|
|
3770
|
+
const errorMessage = this.showSqlInErrors ? `SQL Error: ${error.message}
|
|
3771
|
+
Query: ${truncatedSql}${sqlSuffix}` : `SQL Error: ${error.message}`;
|
|
3772
|
+
throw new errors.DatabaseError(errorMessage, errors$1.DATABASE_ERROR_CODES.QUERY_FAILED, {
|
|
3773
|
+
context: {
|
|
3774
|
+
source: "SQLAdapter.query"
|
|
3775
|
+
},
|
|
3776
|
+
cause: error
|
|
3777
|
+
});
|
|
3775
3778
|
}
|
|
3776
3779
|
}
|
|
3777
3780
|
/**
|
|
@@ -7212,6 +7215,17 @@ var BaseRepository = class {
|
|
|
7212
7215
|
__name(this, "BaseRepository");
|
|
7213
7216
|
}
|
|
7214
7217
|
defaultConfig;
|
|
7218
|
+
/**
|
|
7219
|
+
* Get the table name for this repository
|
|
7220
|
+
*
|
|
7221
|
+
* Useful for transaction operations where you need the table name
|
|
7222
|
+
* to execute raw queries within a transaction context.
|
|
7223
|
+
*
|
|
7224
|
+
* @returns The table name this repository operates on
|
|
7225
|
+
*/
|
|
7226
|
+
getTableName() {
|
|
7227
|
+
return this.tableName;
|
|
7228
|
+
}
|
|
7215
7229
|
/**
|
|
7216
7230
|
* Merges default repository config with per-operation config
|
|
7217
7231
|
* Per-operation config takes precedence over default config
|
|
@@ -10442,6 +10456,10 @@ __name(exports.DataValidationPipe, "DataValidationPipe");
|
|
|
10442
10456
|
exports.DataValidationPipe = __decorateClass([
|
|
10443
10457
|
common.Injectable()
|
|
10444
10458
|
], exports.DataValidationPipe);
|
|
10459
|
+
var DESCRIPTION_MAX_LENGTH = 60;
|
|
10460
|
+
var FALLBACK_DESCRIPTION_LENGTH = 50;
|
|
10461
|
+
var PROGRESS_LOG_INTERVAL = 10;
|
|
10462
|
+
var ERROR_MESSAGE_MAX_LENGTH = 300;
|
|
10445
10463
|
var MigrationManager = class {
|
|
10446
10464
|
static {
|
|
10447
10465
|
__name(this, "MigrationManager");
|
|
@@ -10551,6 +10569,122 @@ var MigrationManager = class {
|
|
|
10551
10569
|
}
|
|
10552
10570
|
return { upSQL: sql2.trim(), downSQL: null };
|
|
10553
10571
|
}
|
|
10572
|
+
/**
|
|
10573
|
+
* Process dollar-quoted string delimiters ($$ or $tag$)
|
|
10574
|
+
* Returns updated state for tracking if we're inside a dollar block
|
|
10575
|
+
*/
|
|
10576
|
+
processDollarDelimiters(line, inDollarBlock, dollarTag) {
|
|
10577
|
+
const dollarMatch = line.match(/\$([a-zA-Z_]*)\$/g);
|
|
10578
|
+
if (!dollarMatch) return { inDollarBlock, dollarTag };
|
|
10579
|
+
let currentInBlock = inDollarBlock;
|
|
10580
|
+
let currentTag = dollarTag;
|
|
10581
|
+
for (const match of dollarMatch) {
|
|
10582
|
+
if (!currentInBlock) {
|
|
10583
|
+
currentInBlock = true;
|
|
10584
|
+
currentTag = match;
|
|
10585
|
+
} else if (match === currentTag) {
|
|
10586
|
+
currentInBlock = false;
|
|
10587
|
+
currentTag = "";
|
|
10588
|
+
}
|
|
10589
|
+
}
|
|
10590
|
+
return { inDollarBlock: currentInBlock, dollarTag: currentTag };
|
|
10591
|
+
}
|
|
10592
|
+
/**
|
|
10593
|
+
* Filter out comment-only statements
|
|
10594
|
+
*/
|
|
10595
|
+
isNonCommentStatement(statement) {
|
|
10596
|
+
const withoutComments = statement.replace(/--.*$/gm, "").trim();
|
|
10597
|
+
return withoutComments.length > 0;
|
|
10598
|
+
}
|
|
10599
|
+
/**
|
|
10600
|
+
* Split SQL into individual statements for better error reporting
|
|
10601
|
+
* Handles $$ delimited blocks (functions, triggers) correctly
|
|
10602
|
+
*/
|
|
10603
|
+
splitSqlStatements(sql2) {
|
|
10604
|
+
const statements = [];
|
|
10605
|
+
let current = "";
|
|
10606
|
+
let inDollarBlock = false;
|
|
10607
|
+
let dollarTag = "";
|
|
10608
|
+
for (const line of sql2.split("\n")) {
|
|
10609
|
+
const trimmedLine = line.trim();
|
|
10610
|
+
const isEmptyOrComment = trimmedLine === "" || trimmedLine.startsWith("--");
|
|
10611
|
+
current += line + "\n";
|
|
10612
|
+
if (isEmptyOrComment) continue;
|
|
10613
|
+
const dollarState = this.processDollarDelimiters(
|
|
10614
|
+
line,
|
|
10615
|
+
inDollarBlock,
|
|
10616
|
+
dollarTag
|
|
10617
|
+
);
|
|
10618
|
+
inDollarBlock = dollarState.inDollarBlock;
|
|
10619
|
+
dollarTag = dollarState.dollarTag;
|
|
10620
|
+
const isEndOfStatement = !inDollarBlock && trimmedLine.endsWith(";");
|
|
10621
|
+
if (isEndOfStatement && current.trim()) {
|
|
10622
|
+
statements.push(current.trim());
|
|
10623
|
+
current = "";
|
|
10624
|
+
}
|
|
10625
|
+
}
|
|
10626
|
+
if (current.trim()) {
|
|
10627
|
+
statements.push(current.trim());
|
|
10628
|
+
}
|
|
10629
|
+
return statements.filter((s) => this.isNonCommentStatement(s));
|
|
10630
|
+
}
|
|
10631
|
+
/**
|
|
10632
|
+
* Extract a short description from a SQL statement for logging
|
|
10633
|
+
*/
|
|
10634
|
+
getStatementDescription(statement) {
|
|
10635
|
+
const firstLine = statement.split("\n").find((l) => l.trim() && !l.trim().startsWith("--"))?.trim() ?? "";
|
|
10636
|
+
const patterns = [
|
|
10637
|
+
/^(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,
|
|
10638
|
+
/^(ALTER\s+TABLE)\s+([^\s]+)/i,
|
|
10639
|
+
/^(DROP\s+(?:TABLE|INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+EXISTS\s+)?([^\s(;]+)/i,
|
|
10640
|
+
/^(INSERT\s+INTO)\s+([^\s(]+)/i,
|
|
10641
|
+
/^(COMMENT\s+ON\s+(?:TABLE|COLUMN|INDEX|FUNCTION|TYPE))\s+([^\s]+)/i,
|
|
10642
|
+
/^(GRANT|REVOKE)\s+.+\s+ON\s+([^\s]+)/i
|
|
10643
|
+
];
|
|
10644
|
+
for (const pattern of patterns) {
|
|
10645
|
+
const match = firstLine.match(pattern);
|
|
10646
|
+
if (match) {
|
|
10647
|
+
return `${match[1]} ${match[2]}`.slice(0, DESCRIPTION_MAX_LENGTH);
|
|
10648
|
+
}
|
|
10649
|
+
}
|
|
10650
|
+
const truncated = firstLine.slice(0, FALLBACK_DESCRIPTION_LENGTH);
|
|
10651
|
+
const suffix = firstLine.length > FALLBACK_DESCRIPTION_LENGTH ? "..." : "";
|
|
10652
|
+
return truncated + suffix;
|
|
10653
|
+
}
|
|
10654
|
+
/**
|
|
10655
|
+
* Execute SQL statements individually with better error reporting
|
|
10656
|
+
*/
|
|
10657
|
+
async executeSqlStatements(adapter, sql2, migrationVersion) {
|
|
10658
|
+
const statements = this.splitSqlStatements(sql2);
|
|
10659
|
+
const total = statements.length;
|
|
10660
|
+
console.log(` → ${total} statements to execute`);
|
|
10661
|
+
for (let i = 0; i < statements.length; i++) {
|
|
10662
|
+
const statement = statements[i];
|
|
10663
|
+
const description = this.getStatementDescription(statement);
|
|
10664
|
+
try {
|
|
10665
|
+
await adapter.query(statement);
|
|
10666
|
+
const isInterval = (i + 1) % PROGRESS_LOG_INTERVAL === 0;
|
|
10667
|
+
const isLast = i === total - 1;
|
|
10668
|
+
const isSignificant = Boolean(
|
|
10669
|
+
description.match(/^(CREATE TABLE|CREATE FUNCTION|CREATE TRIGGER)/i)
|
|
10670
|
+
);
|
|
10671
|
+
if (isInterval || isLast || isSignificant) {
|
|
10672
|
+
console.log(` ✓ [${i + 1}/${total}] ${description}`);
|
|
10673
|
+
}
|
|
10674
|
+
} catch (error) {
|
|
10675
|
+
console.log(` ✗ [${i + 1}/${total}] ${description}`);
|
|
10676
|
+
const rawMessage = error.message;
|
|
10677
|
+
const errorMessage = rawMessage.replace(/^SQL Error:\s*/i, "").replace(/^Failed to execute query:.*?-\s*/i, "").slice(0, ERROR_MESSAGE_MAX_LENGTH);
|
|
10678
|
+
throw new errors.DatabaseError(
|
|
10679
|
+
`Migration ${migrationVersion} failed at statement ${i + 1}/${total}:
|
|
10680
|
+
Statement: ${description}
|
|
10681
|
+
Error: ${errorMessage}`,
|
|
10682
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED,
|
|
10683
|
+
{ cause: error }
|
|
10684
|
+
);
|
|
10685
|
+
}
|
|
10686
|
+
}
|
|
10687
|
+
}
|
|
10554
10688
|
/**
|
|
10555
10689
|
* Load SQL migration from file
|
|
10556
10690
|
*/
|
|
@@ -10562,12 +10696,20 @@ var MigrationManager = class {
|
|
|
10562
10696
|
name: migrationFile.name,
|
|
10563
10697
|
up: /* @__PURE__ */ __name(async (adapter) => {
|
|
10564
10698
|
if (typeof adapter.query === "function") {
|
|
10565
|
-
await
|
|
10699
|
+
await this.executeSqlStatements(
|
|
10700
|
+
adapter,
|
|
10701
|
+
upSQL,
|
|
10702
|
+
migrationFile.version
|
|
10703
|
+
);
|
|
10566
10704
|
}
|
|
10567
10705
|
}, "up"),
|
|
10568
10706
|
down: /* @__PURE__ */ __name(async (adapter) => {
|
|
10569
10707
|
if (downSQL && typeof adapter.query === "function") {
|
|
10570
|
-
await
|
|
10708
|
+
await this.executeSqlStatements(
|
|
10709
|
+
adapter,
|
|
10710
|
+
downSQL,
|
|
10711
|
+
migrationFile.version
|
|
10712
|
+
);
|
|
10571
10713
|
} else {
|
|
10572
10714
|
console.warn(
|
|
10573
10715
|
`[Migrations] No DOWN migration for ${migrationFile.version}`
|
|
@@ -10674,6 +10816,7 @@ var MigrationManager = class {
|
|
|
10674
10816
|
/**
|
|
10675
10817
|
* Run all pending migrations
|
|
10676
10818
|
*/
|
|
10819
|
+
/* eslint-disable max-depth, complexity */
|
|
10677
10820
|
async up(targetVersion) {
|
|
10678
10821
|
try {
|
|
10679
10822
|
await this.initialize();
|
|
@@ -10694,9 +10837,15 @@ var MigrationManager = class {
|
|
|
10694
10837
|
const migration = await this.loadMigration(migrationFile);
|
|
10695
10838
|
const startTime = Date.now();
|
|
10696
10839
|
if (typeof this.adapter.transaction === "function") {
|
|
10697
|
-
await this.adapter.transaction(async () => {
|
|
10840
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10698
10841
|
await migration.up(this.adapter);
|
|
10699
10842
|
});
|
|
10843
|
+
if (!txResult.success) {
|
|
10844
|
+
throw txResult.error ?? new errors.DatabaseError(
|
|
10845
|
+
`Migration ${migration.version} failed`,
|
|
10846
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED
|
|
10847
|
+
);
|
|
10848
|
+
}
|
|
10700
10849
|
} else {
|
|
10701
10850
|
await migration.up(this.adapter);
|
|
10702
10851
|
}
|
|
@@ -10751,9 +10900,15 @@ var MigrationManager = class {
|
|
|
10751
10900
|
const migration = await this.loadMigration(migrationFile);
|
|
10752
10901
|
const startTime = Date.now();
|
|
10753
10902
|
if (typeof this.adapter.transaction === "function") {
|
|
10754
|
-
await this.adapter.transaction(async () => {
|
|
10903
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10755
10904
|
await migration.down(this.adapter);
|
|
10756
10905
|
});
|
|
10906
|
+
if (!txResult.success) {
|
|
10907
|
+
throw txResult.error ?? new errors.DatabaseError(
|
|
10908
|
+
`Rollback ${appliedMigration.version} failed`,
|
|
10909
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED
|
|
10910
|
+
);
|
|
10911
|
+
}
|
|
10757
10912
|
} else {
|
|
10758
10913
|
await migration.down(this.adapter);
|
|
10759
10914
|
}
|
|
@@ -10812,6 +10967,10 @@ var MigrationManager = class {
|
|
|
10812
10967
|
}
|
|
10813
10968
|
}
|
|
10814
10969
|
};
|
|
10970
|
+
var DESCRIPTION_MAX_LENGTH2 = 60;
|
|
10971
|
+
var FALLBACK_DESCRIPTION_LENGTH2 = 50;
|
|
10972
|
+
var PROGRESS_LOG_INTERVAL2 = 10;
|
|
10973
|
+
var ERROR_MESSAGE_MAX_LENGTH2 = 300;
|
|
10815
10974
|
var SeedManager = class {
|
|
10816
10975
|
static {
|
|
10817
10976
|
__name(this, "SeedManager");
|
|
@@ -10880,7 +11039,7 @@ var SeedManager = class {
|
|
|
10880
11039
|
const files = fs__namespace.readdirSync(this.seedsPath);
|
|
10881
11040
|
const seeds = [];
|
|
10882
11041
|
for (const file of files) {
|
|
10883
|
-
const match = file.match(/^(\d+)_(.+)\.(ts|js)$/);
|
|
11042
|
+
const match = file.match(/^(\d+)_(.+)\.(ts|js|sql)$/);
|
|
10884
11043
|
if (match) {
|
|
10885
11044
|
const [, order, name] = match;
|
|
10886
11045
|
seeds.push({
|
|
@@ -10893,9 +11052,141 @@ var SeedManager = class {
|
|
|
10893
11052
|
return seeds.sort((a, b) => a.order - b.order);
|
|
10894
11053
|
}
|
|
10895
11054
|
/**
|
|
10896
|
-
*
|
|
11055
|
+
* Process dollar-quoted string delimiters ($$ or $tag$)
|
|
11056
|
+
*/
|
|
11057
|
+
processDollarDelimiters(line, inDollarBlock, dollarTag) {
|
|
11058
|
+
const dollarMatch = line.match(/\$([a-zA-Z_]*)\$/g);
|
|
11059
|
+
if (!dollarMatch) return { inDollarBlock, dollarTag };
|
|
11060
|
+
let currentInBlock = inDollarBlock;
|
|
11061
|
+
let currentTag = dollarTag;
|
|
11062
|
+
for (const match of dollarMatch) {
|
|
11063
|
+
if (!currentInBlock) {
|
|
11064
|
+
currentInBlock = true;
|
|
11065
|
+
currentTag = match;
|
|
11066
|
+
} else if (match === currentTag) {
|
|
11067
|
+
currentInBlock = false;
|
|
11068
|
+
currentTag = "";
|
|
11069
|
+
}
|
|
11070
|
+
}
|
|
11071
|
+
return { inDollarBlock: currentInBlock, dollarTag: currentTag };
|
|
11072
|
+
}
|
|
11073
|
+
/**
|
|
11074
|
+
* Filter out comment-only statements
|
|
11075
|
+
*/
|
|
11076
|
+
isNonCommentStatement(statement) {
|
|
11077
|
+
const withoutComments = statement.replace(/--.*$/gm, "").trim();
|
|
11078
|
+
return withoutComments.length > 0;
|
|
11079
|
+
}
|
|
11080
|
+
/**
|
|
11081
|
+
* Split SQL into individual statements for better error reporting
|
|
11082
|
+
*/
|
|
11083
|
+
splitSqlStatements(sql2) {
|
|
11084
|
+
const statements = [];
|
|
11085
|
+
let current = "";
|
|
11086
|
+
let inDollarBlock = false;
|
|
11087
|
+
let dollarTag = "";
|
|
11088
|
+
for (const line of sql2.split("\n")) {
|
|
11089
|
+
const trimmedLine = line.trim();
|
|
11090
|
+
const isEmptyOrComment = trimmedLine === "" || trimmedLine.startsWith("--");
|
|
11091
|
+
current += line + "\n";
|
|
11092
|
+
if (isEmptyOrComment) continue;
|
|
11093
|
+
const dollarState = this.processDollarDelimiters(
|
|
11094
|
+
line,
|
|
11095
|
+
inDollarBlock,
|
|
11096
|
+
dollarTag
|
|
11097
|
+
);
|
|
11098
|
+
inDollarBlock = dollarState.inDollarBlock;
|
|
11099
|
+
dollarTag = dollarState.dollarTag;
|
|
11100
|
+
if (!inDollarBlock && trimmedLine.endsWith(";") && current.trim()) {
|
|
11101
|
+
statements.push(current.trim());
|
|
11102
|
+
current = "";
|
|
11103
|
+
}
|
|
11104
|
+
}
|
|
11105
|
+
if (current.trim()) {
|
|
11106
|
+
statements.push(current.trim());
|
|
11107
|
+
}
|
|
11108
|
+
return statements.filter((s) => this.isNonCommentStatement(s));
|
|
11109
|
+
}
|
|
11110
|
+
/**
|
|
11111
|
+
* Extract a short description from a SQL statement for logging
|
|
11112
|
+
*/
|
|
11113
|
+
getStatementDescription(statement) {
|
|
11114
|
+
const firstLine = statement.split("\n").find((l) => l.trim() && !l.trim().startsWith("--"))?.trim() ?? "";
|
|
11115
|
+
const patterns = [
|
|
11116
|
+
/^(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,
|
|
11117
|
+
/^(ALTER\s+TABLE)\s+([^\s]+)/i,
|
|
11118
|
+
/^(DROP\s+(?:TABLE|INDEX|TYPE|FUNCTION|TRIGGER|EXTENSION|SCHEMA|VIEW|POLICY))\s+(?:IF\s+EXISTS\s+)?([^\s(;]+)/i,
|
|
11119
|
+
/^(INSERT\s+INTO)\s+([^\s(]+)/i,
|
|
11120
|
+
/^(COMMENT\s+ON\s+(?:TABLE|COLUMN|INDEX|FUNCTION|TYPE))\s+([^\s]+)/i,
|
|
11121
|
+
/^(GRANT|REVOKE)\s+.+\s+ON\s+([^\s]+)/i
|
|
11122
|
+
];
|
|
11123
|
+
for (const pattern of patterns) {
|
|
11124
|
+
const match = firstLine.match(pattern);
|
|
11125
|
+
if (match) {
|
|
11126
|
+
return `${match[1]} ${match[2]}`.slice(0, DESCRIPTION_MAX_LENGTH2);
|
|
11127
|
+
}
|
|
11128
|
+
}
|
|
11129
|
+
const truncated = firstLine.slice(0, FALLBACK_DESCRIPTION_LENGTH2);
|
|
11130
|
+
const suffix = firstLine.length > FALLBACK_DESCRIPTION_LENGTH2 ? "..." : "";
|
|
11131
|
+
return truncated + suffix;
|
|
11132
|
+
}
|
|
11133
|
+
/**
|
|
11134
|
+
* Execute SQL statements individually with better error reporting
|
|
11135
|
+
*/
|
|
11136
|
+
async executeSqlStatements(sql2, seedName) {
|
|
11137
|
+
const statements = this.splitSqlStatements(sql2);
|
|
11138
|
+
const total = statements.length;
|
|
11139
|
+
console.log(` → ${total} statements to execute`);
|
|
11140
|
+
for (let i = 0; i < statements.length; i++) {
|
|
11141
|
+
const statement = statements[i];
|
|
11142
|
+
const description = this.getStatementDescription(statement);
|
|
11143
|
+
try {
|
|
11144
|
+
await this.adapter.query(statement);
|
|
11145
|
+
const isInterval = (i + 1) % PROGRESS_LOG_INTERVAL2 === 0;
|
|
11146
|
+
const isLast = i === total - 1;
|
|
11147
|
+
const isSignificant = Boolean(description.match(/^(INSERT INTO)/i));
|
|
11148
|
+
if (isInterval || isLast || isSignificant) {
|
|
11149
|
+
console.log(` ✓ [${i + 1}/${total}] ${description}`);
|
|
11150
|
+
}
|
|
11151
|
+
} catch (error) {
|
|
11152
|
+
console.log(` ✗ [${i + 1}/${total}] ${description}`);
|
|
11153
|
+
const rawMessage = error.message;
|
|
11154
|
+
const errorMessage = rawMessage.replace(/^SQL Error:\s*/i, "").replace(/^Failed to execute query:.*?-\s*/i, "").slice(0, ERROR_MESSAGE_MAX_LENGTH2);
|
|
11155
|
+
throw new errors.DatabaseError(
|
|
11156
|
+
`Seed "${seedName}" failed at statement ${i + 1}/${total}:
|
|
11157
|
+
Statement: ${description}
|
|
11158
|
+
Error: ${errorMessage}`,
|
|
11159
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED,
|
|
11160
|
+
{ cause: error }
|
|
11161
|
+
);
|
|
11162
|
+
}
|
|
11163
|
+
}
|
|
11164
|
+
}
|
|
11165
|
+
/**
|
|
11166
|
+
* Load SQL seed from file
|
|
10897
11167
|
*/
|
|
11168
|
+
loadSqlSeed(seedFile) {
|
|
11169
|
+
const sql2 = fs__namespace.readFileSync(seedFile.filePath, "utf-8");
|
|
11170
|
+
return {
|
|
11171
|
+
name: seedFile.name,
|
|
11172
|
+
run: /* @__PURE__ */ __name(async () => {
|
|
11173
|
+
if (typeof this.adapter.query === "function") {
|
|
11174
|
+
await this.executeSqlStatements(sql2, seedFile.name);
|
|
11175
|
+
}
|
|
11176
|
+
}, "run"),
|
|
11177
|
+
// SQL seeds don't have cleanup by default
|
|
11178
|
+
cleanup: void 0
|
|
11179
|
+
};
|
|
11180
|
+
}
|
|
11181
|
+
/**
|
|
11182
|
+
* Load seed from file (supports .ts, .js, and .sql)
|
|
11183
|
+
*/
|
|
11184
|
+
// eslint-disable-next-line complexity
|
|
10898
11185
|
async loadSeed(seedFile) {
|
|
11186
|
+
const ext = path__namespace.extname(seedFile.filePath);
|
|
11187
|
+
if (ext === ".sql") {
|
|
11188
|
+
return this.loadSqlSeed(seedFile);
|
|
11189
|
+
}
|
|
10899
11190
|
const importPath = seedFile.filePath.startsWith("/") ? seedFile.filePath : new URL(`file:///${seedFile.filePath.replace(/\\/g, "/")}`).href;
|
|
10900
11191
|
const seedModule = await import(importPath);
|
|
10901
11192
|
return {
|
|
@@ -10949,9 +11240,15 @@ var SeedManager = class {
|
|
|
10949
11240
|
*/
|
|
10950
11241
|
async executeSeed(seed) {
|
|
10951
11242
|
if (typeof this.adapter.transaction === "function") {
|
|
10952
|
-
await this.adapter.transaction(async () => {
|
|
11243
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
10953
11244
|
await seed.run(this.adapter);
|
|
10954
11245
|
});
|
|
11246
|
+
if (!txResult.success) {
|
|
11247
|
+
throw txResult.error ?? new errors.DatabaseError(
|
|
11248
|
+
`Seed ${seed.name} failed`,
|
|
11249
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED
|
|
11250
|
+
);
|
|
11251
|
+
}
|
|
10955
11252
|
} else {
|
|
10956
11253
|
await seed.run(this.adapter);
|
|
10957
11254
|
}
|
|
@@ -11008,9 +11305,15 @@ var SeedManager = class {
|
|
|
11008
11305
|
async executeCleanup(seed) {
|
|
11009
11306
|
if (!seed.cleanup) return;
|
|
11010
11307
|
if (typeof this.adapter.transaction === "function") {
|
|
11011
|
-
await this.adapter.transaction(async () => {
|
|
11308
|
+
const txResult = await this.adapter.transaction(async () => {
|
|
11012
11309
|
await seed.cleanup(this.adapter);
|
|
11013
11310
|
});
|
|
11311
|
+
if (!txResult.success) {
|
|
11312
|
+
throw txResult.error ?? new errors.DatabaseError(
|
|
11313
|
+
`Seed cleanup for ${seed.name} failed`,
|
|
11314
|
+
errors$1.DATABASE_ERROR_CODES.QUERY_FAILED
|
|
11315
|
+
);
|
|
11316
|
+
}
|
|
11014
11317
|
} else {
|
|
11015
11318
|
await seed.cleanup(this.adapter);
|
|
11016
11319
|
}
|