Try to synchronize time zones across import
This commit is contained in:
@@ -213,55 +213,55 @@ SET session_replication_role = 'origin'; -- Re-enable foreign key checks
|
|||||||
-- Create views for common calculations
|
-- Create views for common calculations
|
||||||
-- product_sales_trends view moved to metrics-schema.sql
|
-- product_sales_trends view moved to metrics-schema.sql
|
||||||
|
|
||||||
-- Historical data tables imported from production
|
-- -- Historical data tables imported from production
|
||||||
CREATE TABLE imported_product_current_prices (
|
-- CREATE TABLE imported_product_current_prices (
|
||||||
price_id BIGSERIAL PRIMARY KEY,
|
-- price_id BIGSERIAL PRIMARY KEY,
|
||||||
pid BIGINT NOT NULL,
|
-- pid BIGINT NOT NULL,
|
||||||
qty_buy SMALLINT NOT NULL,
|
-- qty_buy SMALLINT NOT NULL,
|
||||||
is_min_qty_buy BOOLEAN NOT NULL,
|
-- is_min_qty_buy BOOLEAN NOT NULL,
|
||||||
price_each NUMERIC(10,3) NOT NULL,
|
-- price_each NUMERIC(10,3) NOT NULL,
|
||||||
qty_limit SMALLINT NOT NULL,
|
-- qty_limit SMALLINT NOT NULL,
|
||||||
no_promo BOOLEAN NOT NULL,
|
-- no_promo BOOLEAN NOT NULL,
|
||||||
checkout_offer BOOLEAN NOT NULL,
|
-- checkout_offer BOOLEAN NOT NULL,
|
||||||
active BOOLEAN NOT NULL,
|
-- active BOOLEAN NOT NULL,
|
||||||
date_active TIMESTAMP WITH TIME ZONE,
|
-- date_active TIMESTAMP WITH TIME ZONE,
|
||||||
date_deactive TIMESTAMP WITH TIME ZONE,
|
-- date_deactive TIMESTAMP WITH TIME ZONE,
|
||||||
updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
-- updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
-- );
|
||||||
|
|
||||||
CREATE INDEX idx_imported_product_current_prices_pid ON imported_product_current_prices(pid, active, qty_buy);
|
-- CREATE INDEX idx_imported_product_current_prices_pid ON imported_product_current_prices(pid, active, qty_buy);
|
||||||
CREATE INDEX idx_imported_product_current_prices_checkout ON imported_product_current_prices(checkout_offer, active);
|
-- CREATE INDEX idx_imported_product_current_prices_checkout ON imported_product_current_prices(checkout_offer, active);
|
||||||
CREATE INDEX idx_imported_product_current_prices_deactive ON imported_product_current_prices(date_deactive, active);
|
-- CREATE INDEX idx_imported_product_current_prices_deactive ON imported_product_current_prices(date_deactive, active);
|
||||||
CREATE INDEX idx_imported_product_current_prices_active ON imported_product_current_prices(date_active, active);
|
-- CREATE INDEX idx_imported_product_current_prices_active ON imported_product_current_prices(date_active, active);
|
||||||
|
|
||||||
CREATE TABLE imported_daily_inventory (
|
-- CREATE TABLE imported_daily_inventory (
|
||||||
date DATE NOT NULL,
|
-- date DATE NOT NULL,
|
||||||
pid BIGINT NOT NULL,
|
-- pid BIGINT NOT NULL,
|
||||||
amountsold SMALLINT NOT NULL DEFAULT 0,
|
-- amountsold SMALLINT NOT NULL DEFAULT 0,
|
||||||
times_sold SMALLINT NOT NULL DEFAULT 0,
|
-- times_sold SMALLINT NOT NULL DEFAULT 0,
|
||||||
qtyreceived SMALLINT NOT NULL DEFAULT 0,
|
-- qtyreceived SMALLINT NOT NULL DEFAULT 0,
|
||||||
price NUMERIC(7,2) NOT NULL DEFAULT 0,
|
-- price NUMERIC(7,2) NOT NULL DEFAULT 0,
|
||||||
costeach NUMERIC(7,2) NOT NULL DEFAULT 0,
|
-- costeach NUMERIC(7,2) NOT NULL DEFAULT 0,
|
||||||
stamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
-- stamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
-- updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (date, pid)
|
-- PRIMARY KEY (date, pid)
|
||||||
);
|
-- );
|
||||||
|
|
||||||
CREATE INDEX idx_imported_daily_inventory_pid ON imported_daily_inventory(pid);
|
-- CREATE INDEX idx_imported_daily_inventory_pid ON imported_daily_inventory(pid);
|
||||||
|
|
||||||
CREATE TABLE imported_product_stat_history (
|
-- CREATE TABLE imported_product_stat_history (
|
||||||
pid BIGINT NOT NULL,
|
-- pid BIGINT NOT NULL,
|
||||||
date DATE NOT NULL,
|
-- date DATE NOT NULL,
|
||||||
score NUMERIC(10,2) NOT NULL,
|
-- score NUMERIC(10,2) NOT NULL,
|
||||||
score2 NUMERIC(10,2) NOT NULL,
|
-- score2 NUMERIC(10,2) NOT NULL,
|
||||||
qty_in_baskets SMALLINT NOT NULL,
|
-- qty_in_baskets SMALLINT NOT NULL,
|
||||||
qty_sold SMALLINT NOT NULL,
|
-- qty_sold SMALLINT NOT NULL,
|
||||||
notifies_set SMALLINT NOT NULL,
|
-- notifies_set SMALLINT NOT NULL,
|
||||||
visibility_score NUMERIC(10,2) NOT NULL,
|
-- visibility_score NUMERIC(10,2) NOT NULL,
|
||||||
health_score VARCHAR(5) NOT NULL,
|
-- health_score VARCHAR(5) NOT NULL,
|
||||||
sold_view_score NUMERIC(6,3) NOT NULL,
|
-- sold_view_score NUMERIC(6,3) NOT NULL,
|
||||||
updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
-- updated TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (pid, date)
|
-- PRIMARY KEY (pid, date)
|
||||||
);
|
-- );
|
||||||
|
|
||||||
CREATE INDEX idx_imported_product_stat_history_date ON imported_product_stat_history(date);
|
-- CREATE INDEX idx_imported_product_stat_history_date ON imported_product_stat_history(date);
|
||||||
@@ -38,7 +38,7 @@ const sshConfig = {
|
|||||||
password: process.env.PROD_DB_PASSWORD,
|
password: process.env.PROD_DB_PASSWORD,
|
||||||
database: process.env.PROD_DB_NAME,
|
database: process.env.PROD_DB_NAME,
|
||||||
port: process.env.PROD_DB_PORT || 3306,
|
port: process.env.PROD_DB_PORT || 3306,
|
||||||
timezone: 'Z',
|
timezone: '-05:00', // Production DB always stores times in EST (UTC-5) regardless of DST
|
||||||
},
|
},
|
||||||
localDbConfig: {
|
localDbConfig: {
|
||||||
// PostgreSQL config for local
|
// PostgreSQL config for local
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ const dbConfig = {
|
|||||||
port: process.env.DB_PORT || 5432
|
port: process.env.DB_PORT || 5432
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tables to always protect from being dropped
|
||||||
|
const PROTECTED_TABLES = [
|
||||||
|
'users',
|
||||||
|
'permissions',
|
||||||
|
'user_permissions',
|
||||||
|
'calculate_history',
|
||||||
|
'import_history',
|
||||||
|
'ai_prompts',
|
||||||
|
'ai_validation_performance',
|
||||||
|
'templates',
|
||||||
|
'reusable_images',
|
||||||
|
'imported_daily_inventory',
|
||||||
|
'imported_product_stat_history',
|
||||||
|
'imported_product_current_prices'
|
||||||
|
];
|
||||||
|
|
||||||
// Helper function to output progress in JSON format
|
// Helper function to output progress in JSON format
|
||||||
function outputProgress(data) {
|
function outputProgress(data) {
|
||||||
if (!data.status) {
|
if (!data.status) {
|
||||||
@@ -33,17 +49,6 @@ const CORE_TABLES = [
|
|||||||
'product_categories'
|
'product_categories'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Config tables that must be created
|
|
||||||
const CONFIG_TABLES = [
|
|
||||||
'stock_thresholds',
|
|
||||||
'lead_time_thresholds',
|
|
||||||
'sales_velocity_config',
|
|
||||||
'abc_classification_config',
|
|
||||||
'safety_stock_config',
|
|
||||||
'sales_seasonality',
|
|
||||||
'turnover_config'
|
|
||||||
];
|
|
||||||
|
|
||||||
// Split SQL into individual statements
|
// Split SQL into individual statements
|
||||||
function splitSQLStatements(sql) {
|
function splitSQLStatements(sql) {
|
||||||
// First, normalize line endings
|
// First, normalize line endings
|
||||||
@@ -184,8 +189,8 @@ async function resetDatabase() {
|
|||||||
SELECT string_agg(tablename, ', ') as tables
|
SELECT string_agg(tablename, ', ') as tables
|
||||||
FROM pg_tables
|
FROM pg_tables
|
||||||
WHERE schemaname = 'public'
|
WHERE schemaname = 'public'
|
||||||
AND tablename NOT IN ('users', 'permissions', 'user_permissions', 'calculate_history', 'import_history', 'ai_prompts', 'ai_validation_performance', 'templates', 'reusable_images');
|
AND tablename NOT IN (SELECT unnest($1::text[]));
|
||||||
`);
|
`, [PROTECTED_TABLES]);
|
||||||
|
|
||||||
if (!tablesResult.rows[0].tables) {
|
if (!tablesResult.rows[0].tables) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
@@ -204,7 +209,7 @@ async function resetDatabase() {
|
|||||||
// Drop all tables except users
|
// Drop all tables except users
|
||||||
const tables = tablesResult.rows[0].tables.split(', ');
|
const tables = tablesResult.rows[0].tables.split(', ');
|
||||||
for (const table of tables) {
|
for (const table of tables) {
|
||||||
if (!['users', 'reusable_images'].includes(table)) {
|
if (!PROTECTED_TABLES.includes(table)) {
|
||||||
await client.query(`DROP TABLE IF EXISTS "${table}" CASCADE`);
|
await client.query(`DROP TABLE IF EXISTS "${table}" CASCADE`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +264,9 @@ async function resetDatabase() {
|
|||||||
'category_metrics',
|
'category_metrics',
|
||||||
'brand_metrics',
|
'brand_metrics',
|
||||||
'sales_forecasts',
|
'sales_forecasts',
|
||||||
'abc_classification'
|
'abc_classification',
|
||||||
|
'daily_snapshots',
|
||||||
|
'periodic_metrics'
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
@@ -301,51 +308,67 @@ async function resetDatabase() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < statements.length; i++) {
|
// Start a transaction for better error handling
|
||||||
const stmt = statements[i];
|
await client.query('BEGIN');
|
||||||
try {
|
try {
|
||||||
const result = await client.query(stmt);
|
for (let i = 0; i < statements.length; i++) {
|
||||||
|
const stmt = statements[i];
|
||||||
// Verify if table was created (if this was a CREATE TABLE statement)
|
try {
|
||||||
if (stmt.trim().toLowerCase().startsWith('create table')) {
|
const result = await client.query(stmt);
|
||||||
const tableName = stmt.match(/create\s+table\s+(?:if\s+not\s+exists\s+)?["]?(\w+)["]?/i)?.[1];
|
|
||||||
if (tableName) {
|
// Verify if table was created (if this was a CREATE TABLE statement)
|
||||||
const tableExists = await client.query(`
|
if (stmt.trim().toLowerCase().startsWith('create table')) {
|
||||||
SELECT COUNT(*) as count
|
const tableName = stmt.match(/create\s+table\s+(?:if\s+not\s+exists\s+)?["]?(\w+)["]?/i)?.[1];
|
||||||
FROM information_schema.tables
|
if (tableName) {
|
||||||
WHERE table_schema = 'public'
|
const tableExists = await client.query(`
|
||||||
AND table_name = $1
|
SELECT COUNT(*) as count
|
||||||
`, [tableName]);
|
FROM information_schema.tables
|
||||||
|
WHERE table_schema = 'public'
|
||||||
outputProgress({
|
AND table_name = $1
|
||||||
operation: 'Table Creation Verification',
|
`, [tableName]);
|
||||||
message: {
|
|
||||||
table: tableName,
|
outputProgress({
|
||||||
exists: tableExists.rows[0].count > 0
|
operation: 'Table Creation Verification',
|
||||||
}
|
message: {
|
||||||
});
|
table: tableName,
|
||||||
|
exists: tableExists.rows[0].count > 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outputProgress({
|
||||||
|
operation: 'SQL Progress',
|
||||||
|
message: {
|
||||||
|
statement: i + 1,
|
||||||
|
total: statements.length,
|
||||||
|
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
||||||
|
rowCount: result.rowCount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Commit in chunks of 10 statements to avoid long-running transactions
|
||||||
|
if (i > 0 && i % 10 === 0) {
|
||||||
|
await client.query('COMMIT');
|
||||||
|
await client.query('BEGIN');
|
||||||
|
}
|
||||||
|
} catch (sqlError) {
|
||||||
|
await client.query('ROLLBACK');
|
||||||
|
outputProgress({
|
||||||
|
status: 'error',
|
||||||
|
operation: 'SQL Error',
|
||||||
|
error: sqlError.message,
|
||||||
|
statement: stmt,
|
||||||
|
statementNumber: i + 1
|
||||||
|
});
|
||||||
|
throw sqlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputProgress({
|
|
||||||
operation: 'SQL Progress',
|
|
||||||
message: {
|
|
||||||
statement: i + 1,
|
|
||||||
total: statements.length,
|
|
||||||
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
|
||||||
rowCount: result.rowCount
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (sqlError) {
|
|
||||||
outputProgress({
|
|
||||||
status: 'error',
|
|
||||||
operation: 'SQL Error',
|
|
||||||
error: sqlError.message,
|
|
||||||
statement: stmt,
|
|
||||||
statementNumber: i + 1
|
|
||||||
});
|
|
||||||
throw sqlError;
|
|
||||||
}
|
}
|
||||||
|
// Commit the final transaction
|
||||||
|
await client.query('COMMIT');
|
||||||
|
} catch (error) {
|
||||||
|
await client.query('ROLLBACK');
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify core tables were created
|
// Verify core tables were created
|
||||||
@@ -383,11 +406,25 @@ async function resetDatabase() {
|
|||||||
operation: 'Running config setup',
|
operation: 'Running config setup',
|
||||||
message: 'Creating configuration tables...'
|
message: 'Creating configuration tables...'
|
||||||
});
|
});
|
||||||
const configSchemaSQL = fs.readFileSync(
|
const configSchemaPath = path.join(__dirname, '../db/config-schema-new.sql');
|
||||||
path.join(__dirname, '../db/config-schema-new.sql'),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Verify file exists
|
||||||
|
if (!fs.existsSync(configSchemaPath)) {
|
||||||
|
throw new Error(`Config schema file not found at: ${configSchemaPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const configSchemaSQL = fs.readFileSync(configSchemaPath, 'utf8');
|
||||||
|
|
||||||
|
outputProgress({
|
||||||
|
operation: 'Config Schema file',
|
||||||
|
message: {
|
||||||
|
path: configSchemaPath,
|
||||||
|
exists: fs.existsSync(configSchemaPath),
|
||||||
|
size: fs.statSync(configSchemaPath).size,
|
||||||
|
firstFewLines: configSchemaSQL.split('\n').slice(0, 5).join('\n')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Execute config schema statements one at a time
|
// Execute config schema statements one at a time
|
||||||
const configStatements = splitSQLStatements(configSchemaSQL);
|
const configStatements = splitSQLStatements(configSchemaSQL);
|
||||||
outputProgress({
|
outputProgress({
|
||||||
@@ -401,30 +438,46 @@ async function resetDatabase() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < configStatements.length; i++) {
|
// Start a transaction for better error handling
|
||||||
const stmt = configStatements[i];
|
await client.query('BEGIN');
|
||||||
try {
|
try {
|
||||||
const result = await client.query(stmt);
|
for (let i = 0; i < configStatements.length; i++) {
|
||||||
|
const stmt = configStatements[i];
|
||||||
outputProgress({
|
try {
|
||||||
operation: 'Config SQL Progress',
|
const result = await client.query(stmt);
|
||||||
message: {
|
|
||||||
statement: i + 1,
|
outputProgress({
|
||||||
total: configStatements.length,
|
operation: 'Config SQL Progress',
|
||||||
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
message: {
|
||||||
rowCount: result.rowCount
|
statement: i + 1,
|
||||||
|
total: configStatements.length,
|
||||||
|
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
||||||
|
rowCount: result.rowCount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Commit in chunks of 10 statements to avoid long-running transactions
|
||||||
|
if (i > 0 && i % 10 === 0) {
|
||||||
|
await client.query('COMMIT');
|
||||||
|
await client.query('BEGIN');
|
||||||
}
|
}
|
||||||
});
|
} catch (sqlError) {
|
||||||
} catch (sqlError) {
|
await client.query('ROLLBACK');
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
operation: 'Config SQL Error',
|
operation: 'Config SQL Error',
|
||||||
error: sqlError.message,
|
error: sqlError.message,
|
||||||
statement: stmt,
|
statement: stmt,
|
||||||
statementNumber: i + 1
|
statementNumber: i + 1
|
||||||
});
|
});
|
||||||
throw sqlError;
|
throw sqlError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Commit the final transaction
|
||||||
|
await client.query('COMMIT');
|
||||||
|
} catch (error) {
|
||||||
|
await client.query('ROLLBACK');
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and execute metrics schema (metrics tables)
|
// Read and execute metrics schema (metrics tables)
|
||||||
@@ -432,11 +485,25 @@ async function resetDatabase() {
|
|||||||
operation: 'Running metrics setup',
|
operation: 'Running metrics setup',
|
||||||
message: 'Creating metrics tables...'
|
message: 'Creating metrics tables...'
|
||||||
});
|
});
|
||||||
const metricsSchemaSQL = fs.readFileSync(
|
const metricsSchemaPath = path.join(__dirname, '../db/metrics-schema-new.sql');
|
||||||
path.join(__dirname, '../db/metrics-schema-new.sql'),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Verify file exists
|
||||||
|
if (!fs.existsSync(metricsSchemaPath)) {
|
||||||
|
throw new Error(`Metrics schema file not found at: ${metricsSchemaPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const metricsSchemaSQL = fs.readFileSync(metricsSchemaPath, 'utf8');
|
||||||
|
|
||||||
|
outputProgress({
|
||||||
|
operation: 'Metrics Schema file',
|
||||||
|
message: {
|
||||||
|
path: metricsSchemaPath,
|
||||||
|
exists: fs.existsSync(metricsSchemaPath),
|
||||||
|
size: fs.statSync(metricsSchemaPath).size,
|
||||||
|
firstFewLines: metricsSchemaSQL.split('\n').slice(0, 5).join('\n')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Execute metrics schema statements one at a time
|
// Execute metrics schema statements one at a time
|
||||||
const metricsStatements = splitSQLStatements(metricsSchemaSQL);
|
const metricsStatements = splitSQLStatements(metricsSchemaSQL);
|
||||||
outputProgress({
|
outputProgress({
|
||||||
@@ -450,30 +517,46 @@ async function resetDatabase() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < metricsStatements.length; i++) {
|
// Start a transaction for better error handling
|
||||||
const stmt = metricsStatements[i];
|
await client.query('BEGIN');
|
||||||
try {
|
try {
|
||||||
const result = await client.query(stmt);
|
for (let i = 0; i < metricsStatements.length; i++) {
|
||||||
|
const stmt = metricsStatements[i];
|
||||||
outputProgress({
|
try {
|
||||||
operation: 'Metrics SQL Progress',
|
const result = await client.query(stmt);
|
||||||
message: {
|
|
||||||
statement: i + 1,
|
outputProgress({
|
||||||
total: metricsStatements.length,
|
operation: 'Metrics SQL Progress',
|
||||||
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
message: {
|
||||||
rowCount: result.rowCount
|
statement: i + 1,
|
||||||
|
total: metricsStatements.length,
|
||||||
|
preview: stmt.substring(0, 100) + (stmt.length > 100 ? '...' : ''),
|
||||||
|
rowCount: result.rowCount
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Commit in chunks of 10 statements to avoid long-running transactions
|
||||||
|
if (i > 0 && i % 10 === 0) {
|
||||||
|
await client.query('COMMIT');
|
||||||
|
await client.query('BEGIN');
|
||||||
}
|
}
|
||||||
});
|
} catch (sqlError) {
|
||||||
} catch (sqlError) {
|
await client.query('ROLLBACK');
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'error',
|
status: 'error',
|
||||||
operation: 'Metrics SQL Error',
|
operation: 'Metrics SQL Error',
|
||||||
error: sqlError.message,
|
error: sqlError.message,
|
||||||
statement: stmt,
|
statement: stmt,
|
||||||
statementNumber: i + 1
|
statementNumber: i + 1
|
||||||
});
|
});
|
||||||
throw sqlError;
|
throw sqlError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Commit the final transaction
|
||||||
|
await client.query('COMMIT');
|
||||||
|
} catch (error) {
|
||||||
|
await client.query('ROLLBACK');
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputProgress({
|
outputProgress({
|
||||||
@@ -490,6 +573,14 @@ async function resetDatabase() {
|
|||||||
});
|
});
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} finally {
|
} finally {
|
||||||
|
// Make sure to re-enable foreign key checks if they were disabled
|
||||||
|
try {
|
||||||
|
await client.query('SET session_replication_role = \'origin\'');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error re-enabling foreign key checks:', e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the database connection
|
||||||
await client.end();
|
await client.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ const PROTECTED_TABLES = [
|
|||||||
'ai_prompts',
|
'ai_prompts',
|
||||||
'ai_validation_performance',
|
'ai_validation_performance',
|
||||||
'templates',
|
'templates',
|
||||||
'reusable_images'
|
'reusable_images',
|
||||||
|
'imported_daily_inventory',
|
||||||
|
'imported_product_stat_history',
|
||||||
|
'imported_product_current_prices'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Split SQL into individual statements
|
// Split SQL into individual statements
|
||||||
|
|||||||
Reference in New Issue
Block a user