/
diloytd
/
shield
Обзор
Документация
Войти
/
diloytd
/
shield
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/database/schema.js
214 строк
7 KB
diloytd
Перепроектировать shields.json и поддержать ТУ, сертификаты и новые условия.
22 июл 2026, 17:14
22 июл 2026, 17:14
fb8b887
Код
Авторство
О чём код?
/** * SQL-схема базы данных ShieldJournal. * Содержит только создание таблиц, без логики подключения. */ const { migrateExistingOrders } = require('../services/numberingService'); /** * Удаляет ограничение UNIQUE на Shields.instanceId в существующей базе. * Нужно для перехода от связи 1:1 к связи 1:N (несколько шильдов на экземпляр). * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const migrateShieldsOneToMany = (db) => { const tableInfo = db.prepare(` SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'Shields' `).get(); if (!tableInfo || !tableInfo.sql) { return; } const hasUniqueOnInstanceId = /instanceId\s+INTEGER\s+NOT\s+NULL\s+UNIQUE/i.test(tableInfo.sql); if (hasUniqueOnInstanceId) { db.exec(` CREATE TABLE Shields_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, instanceId INTEGER NOT NULL, shieldNumber TEXT, shieldType TEXT, marking TEXT, fireResistance TEXT, TU TEXT, productionDate DATE, FOREIGN KEY (instanceId) REFERENCES ProductInstances(id) ON DELETE CASCADE ); INSERT INTO Shields_new ( id, instanceId, shieldNumber, shieldType, marking, fireResistance, TU, productionDate ) SELECT id, instanceId, shieldNumber, shieldType, NULL AS marking, fireResistance, TU, productionDate FROM Shields; DROP TABLE Shields; ALTER TABLE Shields_new RENAME TO Shields; `); } const uniqueIndexes = db.prepare(` SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = 'Shields' AND sql IS NOT NULL `).all(); uniqueIndexes.forEach((index) => { if (index.sql.includes('UNIQUE') && index.sql.includes('instanceId')) { db.exec(`DROP INDEX IF EXISTS "${index.name}"`); } }); }; /** * Добавляет колонку marking в таблицу Shields для существующих баз данных. * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const migrateShieldsMarkingColumn = (db) => { const columnInfo = db.prepare(` SELECT name FROM pragma_table_info('Shields') WHERE name = 'marking' `).get(); if (columnInfo) { return; } db.exec('ALTER TABLE Shields ADD COLUMN marking TEXT'); }; /** * Добавляет колонку certificates в таблицу Shields для существующих баз данных. * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const migrateShieldsCertificatesColumn = (db) => { const columnInfo = db.prepare(` SELECT name FROM pragma_table_info('Shields') WHERE name = 'certificates' `).get(); if (columnInfo) { return; } db.exec('ALTER TABLE Shields ADD COLUMN certificates TEXT'); }; /** * Добавляет колонки dropThreshold и constructionType в LogicalProducts. * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const migrateLogicalProductsConditionColumns = (db) => { const columns = db.prepare(` SELECT name FROM pragma_table_info('LogicalProducts') `).all().map((row) => row.name); if (!columns.includes('dropThreshold')) { db.exec('ALTER TABLE LogicalProducts ADD COLUMN dropThreshold BOOLEAN'); } if (!columns.includes('constructionType')) { db.exec('ALTER TABLE LogicalProducts ADD COLUMN constructionType TEXT'); } }; /** * Создаёт таблицы нумерации журнала, если они ещё не существуют. * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const createNumberingTables = (db) => { db.exec(` CREATE TABLE IF NOT EXISTS JournalCounters ( id INTEGER PRIMARY KEY CHECK (id = 1), nextEntryNumber INTEGER NOT NULL, nextShieldNumber INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS JournalEntries ( id INTEGER PRIMARY KEY AUTOINCREMENT, orderId INTEGER NOT NULL UNIQUE, entryNumber INTEGER NOT NULL UNIQUE, productionDate DATE NOT NULL, FOREIGN KEY (orderId) REFERENCES Orders(id) ON DELETE CASCADE ); `); migrateExistingOrders(db); }; /** * Создаёт все таблицы базы данных, если они ещё не существуют. * Схема соответствует docs/database.md. * Внешние ключи используют ON DELETE CASCADE для каскадного удаления * по цепочке: Заказ → Позиция → Логическое изделие → Экземпляр → Шильд. * @param {import('better-sqlite3').Database} db - Экземпляр подключения к SQLite. * @returns {void} */ const createTables = (db) => { db.exec(` CREATE TABLE IF NOT EXISTS Orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, number TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS OrderPositions ( id INTEGER PRIMARY KEY AUTOINCREMENT, orderId INTEGER NOT NULL, number INTEGER NOT NULL, FOREIGN KEY (orderId) REFERENCES Orders(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS LogicalProducts ( id INTEGER PRIMARY KEY AUTOINCREMENT, positionId INTEGER NOT NULL, type TEXT NOT NULL, systemName TEXT, fireResistance TEXT, openingType TEXT, glassType TEXT, doorType TEXT, hasFramuga BOOLEAN, hasDoor BOOLEAN, dropThreshold BOOLEAN, constructionType TEXT, FOREIGN KEY (positionId) REFERENCES OrderPositions(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS ProductInstances ( id INTEGER PRIMARY KEY AUTOINCREMENT, logicalProductId INTEGER NOT NULL, number INTEGER NOT NULL, FOREIGN KEY (logicalProductId) REFERENCES LogicalProducts(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS Shields ( id INTEGER PRIMARY KEY AUTOINCREMENT, instanceId INTEGER NOT NULL, shieldNumber TEXT, shieldType TEXT, marking TEXT, fireResistance TEXT, TU TEXT, certificates TEXT, productionDate DATE, FOREIGN KEY (instanceId) REFERENCES ProductInstances(id) ON DELETE CASCADE ); `); migrateShieldsOneToMany(db); migrateShieldsMarkingColumn(db); migrateShieldsCertificatesColumn(db); migrateLogicalProductsConditionColumns(db); createNumberingTables(db); }; module.exports = { createTables, createNumberingTables, migrateShieldsMarkingColumn, migrateShieldsCertificatesColumn, migrateLogicalProductsConditionColumns, migrateShieldsOneToMany, };