60 lines
3.2 KiB
TypeScript
60 lines
3.2 KiB
TypeScript
|
|
import type { Sequelize } from "sequelize";
|
||
|
|
import { QueryTypes } from "sequelize";
|
||
|
|
|
||
|
|
/** Proyección estructural mínima; Resource conserva identidad, datos editables, estado e historial. */
|
||
|
|
export async function migrateDirectoryDomains(database: Sequelize) {
|
||
|
|
for (const [table, fields, name] of [
|
||
|
|
["resources", ["id", "companyId", "templateId"], "directory_resource_scope_template"],
|
||
|
|
["resource_definitions", ["id", "stockKey"], "directory_template_key"],
|
||
|
|
] as const) {
|
||
|
|
const indexes = await database.query<{ name: string }>(
|
||
|
|
"SELECT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=:table AND INDEX_NAME=:name",
|
||
|
|
{ replacements: { table, name }, type: QueryTypes.SELECT }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!indexes.length) {
|
||
|
|
await database.getQueryInterface().addIndex(table, [...fields], { name, unique: true });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
await database.query(`CREATE TABLE IF NOT EXISTS resource_directory_domains (
|
||
|
|
resourceId CHAR(36) BINARY NOT NULL PRIMARY KEY,
|
||
|
|
companyId CHAR(36) BINARY NOT NULL,
|
||
|
|
templateId CHAR(36) BINARY NOT NULL,
|
||
|
|
templateKey VARCHAR(100) NOT NULL DEFAULT 'template:windows_domain',
|
||
|
|
normalizedDns VARCHAR(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL,
|
||
|
|
environmentId CHAR(36) BINARY NOT NULL,
|
||
|
|
associatedBy CHAR(36) BINARY NOT NULL,
|
||
|
|
associatedAt VARCHAR(30) NOT NULL,
|
||
|
|
UNIQUE KEY directory_dns_company (companyId,normalizedDns),
|
||
|
|
UNIQUE KEY directory_environment_unique (environmentId),
|
||
|
|
CONSTRAINT directory_template_semantics CHECK (templateKey='template:windows_domain'),
|
||
|
|
CONSTRAINT directory_dns_not_empty CHECK (CHAR_LENGTH(normalizedDns)>0),
|
||
|
|
CONSTRAINT directory_resource FOREIGN KEY (resourceId,companyId,templateId) REFERENCES resources(id,companyId,templateId),
|
||
|
|
CONSTRAINT directory_template FOREIGN KEY (templateId,templateKey) REFERENCES resource_definitions(id,stockKey),
|
||
|
|
CONSTRAINT directory_context FOREIGN KEY (environmentId,companyId) REFERENCES access_directory_environments(environmentId,companyId),
|
||
|
|
CONSTRAINT directory_association_actor FOREIGN KEY (associatedBy) REFERENCES users(id)
|
||
|
|
) ENGINE=InnoDB`);
|
||
|
|
const scopeIndex = await database.query<{ name: string }>(
|
||
|
|
"SELECT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='resource_directory_domains' AND INDEX_NAME='directory_resource_company'",
|
||
|
|
{ type: QueryTypes.SELECT }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!scopeIndex.length) {
|
||
|
|
await database
|
||
|
|
.getQueryInterface()
|
||
|
|
.addIndex("resource_directory_domains", ["resourceId", "companyId"], {
|
||
|
|
name: "directory_resource_company",
|
||
|
|
unique: true,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
const canonical = await database.query<{ name: string }>(
|
||
|
|
"SELECT CONSTRAINT_NAME AS name FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='resource_directory_domains' AND CONSTRAINT_NAME='directory_dns_canonical'",
|
||
|
|
{ type: QueryTypes.SELECT }
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!canonical.length) {
|
||
|
|
await database.query(`ALTER TABLE resource_directory_domains ADD CONSTRAINT directory_dns_canonical
|
||
|
|
CHECK (normalizedDns=LOWER(normalizedDns) AND LENGTH(normalizedDns)=LENGTH(TRIM(normalizedDns)) AND RIGHT(normalizedDns,1)<>'.')`);
|
||
|
|
}
|
||
|
|
}
|