fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
77
scripts/migrate-docker.js
Normal file
77
scripts/migrate-docker.js
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Docker-friendly migration runner.
|
||||
* Applies SQL files from ./migrations/ in order using pg directly,
|
||||
* without drizzle-kit (which can hang in non-TTY Docker environments).
|
||||
*/
|
||||
|
||||
import pg from "pg";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const MIGRATIONS_DIR = path.resolve(__dirname, "../migrations");
|
||||
|
||||
const url = process.env.DATABASE_URL;
|
||||
if (!url) {
|
||||
console.error("[Migrate] ERROR: DATABASE_URL is not set.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new pg.Client({ connectionString: url });
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS __drizzle_migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
)
|
||||
`);
|
||||
|
||||
const { rows: applied } = await client.query(
|
||||
"SELECT name FROM __drizzle_migrations ORDER BY id"
|
||||
);
|
||||
const appliedSet = new Set(applied.map((r) => r.name));
|
||||
|
||||
const files = fs
|
||||
.readdirSync(MIGRATIONS_DIR)
|
||||
.filter((f) => f.endsWith(".sql"))
|
||||
.sort();
|
||||
|
||||
let count = 0;
|
||||
for (const file of files) {
|
||||
if (appliedSet.has(file)) continue;
|
||||
|
||||
const sql = fs.readFileSync(path.join(MIGRATIONS_DIR, file), "utf8");
|
||||
console.log(`[Migrate] Applying ${file}…`);
|
||||
await client.query("BEGIN");
|
||||
try {
|
||||
await client.query(sql);
|
||||
await client.query(
|
||||
"INSERT INTO __drizzle_migrations (name) VALUES ($1)",
|
||||
[file]
|
||||
);
|
||||
await client.query("COMMIT");
|
||||
count++;
|
||||
} catch (err) {
|
||||
await client.query("ROLLBACK");
|
||||
console.error(`[Migrate] ERROR in ${file}:`, err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (count === 0) {
|
||||
console.log("[Migrate] All migrations already applied, nothing to do.");
|
||||
} else {
|
||||
console.log(`[Migrate] Done — applied ${count} migration(s).`);
|
||||
}
|
||||
|
||||
await client.end();
|
||||
} catch (err) {
|
||||
console.error("[Migrate] Fatal error:", err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user