import { PrismaMssql } from "@prisma/adapter-mssql"; import { Prisma, PrismaClient } from "./generated/prisma/client"; const connectionString = process.env.DATABASE_URL; if (!connectionString) { throw new Error("DATABASE_URL is not set."); } const adapter = new PrismaMssql(connectionString); const prisma = new PrismaClient({ adapter }); type CandidateTable = { table_name: string }; type CandidateColumn = { table_name: string; column_name: string }; type DmmfField = { name: string; dbName: string | null; }; type DmmfModel = { name: string; dbName: string | null; fields: DmmfField[]; }; const TABLE_PATTERN = /config|configur/i; const VALUE_COLUMN_PATTERN = /value|field|question|token/i; const TOP_CONFIG_LIMIT = 150; const CONFIG_KEY_COLUMNS = new Set([ "Config_RecID", "Configuration_RecID", "Configuration_RecId", ]); function byName(a: string, b: string) { return a.localeCompare(b); } try { const models = Prisma.dmmf.datamodel.models as unknown as DmmfModel[]; const configModels = models .map((model) => ({ model, tableName: model.dbName ?? model.name, })) .filter(({ tableName }) => TABLE_PATTERN.test(tableName)); const candidateTables: CandidateTable[] = configModels .map(({ tableName }) => ({ table_name: tableName })) .sort((a, b) => byName(a.table_name, b.table_name)); const candidateColumns: CandidateColumn[] = configModels .flatMap(({ model, tableName }) => model.fields .map((field) => field.dbName ?? field.name) .filter((columnName) => VALUE_COLUMN_PATTERN.test(columnName)) .map((columnName) => ({ table_name: tableName, column_name: columnName, })) ) .sort( (a, b) => byName(a.table_name, b.table_name) || byName(a.column_name, b.column_name) ); const valueTablesWithConfigKey: CandidateTable[] = configModels .filter(({ model }) => { const columnNames = model.fields.map( (field) => field.dbName ?? field.name ); const hasConfigKey = columnNames.some((column) => CONFIG_KEY_COLUMNS.has(column) ); const hasValueLikeColumn = columnNames.some((column) => VALUE_COLUMN_PATTERN.test(column) ); return hasConfigKey && hasValueLikeColumn; }) .map(({ tableName }) => ({ table_name: tableName })) .sort((a, b) => byName(a.table_name, b.table_name)); const [ configRows, auditRows, auditValueRows, nonNullCustomFields, groupedAuditTokens, topConfigs, ] = await prisma.$transaction([ prisma.configuration.count(), prisma.configurationAudit.count(), prisma.configurationAuditValue.count(), prisma.configuration.findMany({ where: { customField: { not: null } }, select: { customField: true }, }), prisma.configurationAuditValue.groupBy({ by: ["auditToken"], _count: true, orderBy: [{ _count: { auditToken: "desc" } }, { auditToken: "asc" }], take: 20, }), prisma.configuration.findMany({ take: TOP_CONFIG_LIMIT, orderBy: { configRecId: "asc" }, include: { configurationAudits: { orderBy: { configurationAuditRecId: "asc" }, include: { configurationValues: { orderBy: { configurationAuditValueRecId: "asc" }, }, }, }, }, }), ]); const configCustomFieldNonempty = nonNullCustomFields.reduce((count, row) => { return row.customField?.trim() ? count + 1 : count; }, 0); const rowStats = { config_rows: configRows, config_custom_field_nonempty: configCustomFieldNonempty, audit_rows: auditRows, audit_value_rows: auditValueRows, }; const topAuditTokens = groupedAuditTokens.map(({ auditToken, _count }) => ({ audit_token: auditToken, row_count: _count, })); const output = { candidateTables, candidateColumns, valueTablesWithConfigKey, rowStats, topAuditTokens, topConfigs, }; console.log(JSON.stringify(output, null, 2)); } finally { await prisma.$disconnect(); }