chore(global): remove a bunch of test and temp files

This commit is contained in:
2026-04-17 22:34:41 +00:00
parent a8c48e8c75
commit 5141ed20f9
23 changed files with 185 additions and 2529 deletions
-76
View File
@@ -1,76 +0,0 @@
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaClient } from "./generated/prisma/client";
const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
throw new Error("DATABASE_URL is not set.");
}
const prisma = new PrismaClient({
adapter: new PrismaMssql(connectionString),
});
try {
const rowSummary = await prisma.$queryRawUnsafe<
Array<{ total_rows: number; distinct_configs: number }>
>(`
SELECT
COUNT(*) AS total_rows,
COUNT(DISTINCT Config_RecID) AS distinct_configs
FROM dbo.Config_User_Defined_Field_Value;
`);
const relatedRowCounts = await prisma.$queryRawUnsafe<
Array<{
config_rows: number;
cs_result_detail_rows: number;
config_custom_field_nonempty: number;
}>
>(`
SELECT
(SELECT COUNT(*) FROM dbo.Config) AS config_rows,
(SELECT COUNT(*) FROM dbo.CS_Result_Detail) AS cs_result_detail_rows,
(SELECT COUNT(*)
FROM dbo.Config
WHERE Custom_Field IS NOT NULL
AND LEN(LTRIM(RTRIM(CONVERT(nvarchar(max), Custom_Field)))) > 0) AS config_custom_field_nonempty;
`);
const topConfigs = await prisma.$queryRawUnsafe<
Array<{ config_recid: number; field_count: number }>
>(`
SELECT TOP 10
Config_RecID AS config_recid,
COUNT(*) AS field_count
FROM dbo.Config_User_Defined_Field_Value
GROUP BY Config_RecID
ORDER BY field_count DESC, config_recid ASC;
`);
const customFieldSamples = await prisma.$queryRawUnsafe<
Array<{ config_recid: number; custom_field_prefix: string }>
>(`
SELECT TOP 5
Config_RecID AS config_recid,
LEFT(CONVERT(nvarchar(max), Custom_Field), 250) AS custom_field_prefix
FROM dbo.Config
WHERE Custom_Field IS NOT NULL
AND LEN(LTRIM(RTRIM(CONVERT(nvarchar(max), Custom_Field)))) > 0
ORDER BY Config_RecID ASC;
`);
console.log(
JSON.stringify(
{
rowSummary: rowSummary[0] ?? null,
relatedRowCounts: relatedRowCounts[0] ?? null,
topConfigs,
customFieldSamples,
},
null,
2,
),
);
} finally {
await prisma.$disconnect();
}
-43
View File
@@ -1,43 +0,0 @@
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaClient } from "./generated/prisma/client";
import { writeFileSync } from "node:fs";
const outputPath =
process.argv[2] ??
process.env.CONFIG_OUTPUT_FILE ??
"configurations-first-10-with-relations.json";
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 });
try {
const configurations = await prisma.configuration.findMany({
take: 10,
orderBy: { configRecId: "asc" },
include: {
configStatus: true,
configurationAudits: {
orderBy: { lastUpdatedUtc: "desc" },
include: {
configurationValues: {
orderBy: { configurationAuditValueRecId: "asc" },
},
},
},
},
});
if (configurations.length === 0) {
console.error("No configurations found.");
process.exit(1);
}
writeFileSync(outputPath, JSON.stringify(configurations, null, 2));
} finally {
await prisma.$disconnect();
}
-19
View File
@@ -1,19 +0,0 @@
import fetchOpportunities from "./old-src/collectors/fetchOpportunities";
fetchOpportunities({
include: [
"company",
"activities",
"opportunityNotes",
"forecastItems",
"contacts",
],
}).then((opportunities) => {
const jsonData = JSON.stringify(opportunities, null, 2);
const { writeFileSync } = require("fs");
writeFileSync("examples/opportunity-with-relations.json", jsonData);
console.log(
`Exported ${opportunities.length} opportunities to examples/opportunity-with-relations.json`
);
process.exit(0);
});
-30
View File
@@ -1,30 +0,0 @@
import { PrismaClient } from "./generated/prisma/client";
import { PrismaMssql } from "@prisma/adapter-mssql";
import { writeFileSync } from "fs";
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 });
const products = await prisma.productCatalog.findMany({
where: { inactiveFlag: false },
include: {
subcategory: { include: { category: true } },
manufacturer: true,
inventory: true,
itemVendors: true,
},
take: 100,
});
writeFileSync(
"products-with-relations.json",
JSON.stringify(products, null, 2),
);
console.log(`Exported ${products.length} products`);
await prisma.$disconnect();
@@ -1,150 +0,0 @@
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();
}
@@ -1,334 +0,0 @@
import { PrismaMssql } from "@prisma/adapter-mssql";
import { PrismaPg } from "@prisma/adapter-pg";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { PrismaClient as CwPrismaClient } from "./generated/prisma/client";
import { PrismaClient as ApiPrismaClient } from "../api/generated/prisma/client";
type EnvMap = Record<string, string>;
type Summary = {
cwTotal: number;
apiTotal: number;
eligibleForSync: number;
missingSrServiceRecId: number;
missingMemberRecId: number;
missingParentTicketInApi: number;
missingAuthorMappingInApi: number;
eligibleButMissingInApi: number;
sampleMissingParentTicketIds: number[];
sampleMissingAuthorMemberRecIds: number[];
sampleEligibleButMissingNoteIds: number[];
topMissingAuthorMemberRecIds: Array<{ memberRecId: number; count: number }>;
topMissingParentTicketIds: Array<{ srServiceRecId: number; count: number }>;
automateApi: {
total: number;
eligibleForSync: number;
missingSrServiceRecId: number;
missingMemberRecId: number;
missingParentTicketInApi: number;
missingAuthorMappingInApi: number;
eligibleButMissingInApi: number;
sampleMemberRecIds: number[];
sampleNoteIdsMissingInApi: number[];
};
};
const isAutomateApiAuthor = (
createdBy: string | null,
originalAuthor: string | null
): boolean => {
const normalizedCreatedBy = createdBy?.trim().toLowerCase() ?? "";
const normalizedOriginalAuthor = originalAuthor?.trim().toLowerCase() ?? "";
return (
normalizedCreatedBy.includes("automateapi") ||
normalizedOriginalAuthor.includes("automateapi")
);
};
const parseEnvFile = (path: string): EnvMap => {
const envData = readFileSync(path, "utf8");
const out: EnvMap = {};
for (const rawLine of envData.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line || line.startsWith("#")) continue;
const index = line.indexOf("=");
if (index <= 0) continue;
const key = line.slice(0, index).trim();
let value = line.slice(index + 1).trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
out[key] = value;
}
return out;
};
const readApiEnv = (): EnvMap => {
const candidates = [
resolve(import.meta.dir, "../api/.env"),
resolve(process.cwd(), "../api/.env"),
resolve(process.cwd(), "api/.env"),
];
for (const candidate of candidates) {
try {
return parseEnvFile(candidate);
} catch {
// Try next
}
}
return {};
};
const main = async (): Promise<void> => {
const apiEnv = readApiEnv();
const cwDatabaseUrl =
process.env.CW_DATABASE_URL ||
process.env.DATABASE_URL ||
apiEnv.CW_DATABASE_URL;
const apiDatabaseUrl =
process.env.API_DATABASE_URL ||
process.env.OPTIMA_API_DATABASE_URL ||
apiEnv.API_DATABASE_URL ||
apiEnv.OPTIMA_API_DATABASE_URL ||
apiEnv.DATABASE_URL;
if (!cwDatabaseUrl) {
throw new Error("Missing CW DB URL. Set CW_DATABASE_URL or DATABASE_URL.");
}
if (!apiDatabaseUrl) {
throw new Error(
"Missing API DB URL. Set API_DATABASE_URL/OPTIMA_API_DATABASE_URL or provide api/.env DATABASE_URL."
);
}
const cwPrisma = new CwPrismaClient({
adapter: new PrismaMssql(cwDatabaseUrl),
});
const apiPrisma = new ApiPrismaClient({
adapter: new PrismaPg({ connectionString: apiDatabaseUrl }),
});
try {
console.log("[diag] Loading API reference sets...");
const [apiNotes, apiTickets, apiUsers] = await Promise.all([
apiPrisma.serviceTicketNote.findMany({ select: { id: true } }),
apiPrisma.serviceTicket.findMany({ select: { id: true } }),
apiPrisma.user.findMany({ select: { cwMemberId: true } }),
]);
const apiNoteIds = new Set<number>(apiNotes.map((r) => r.id));
const apiTicketIds = new Set<number>(apiTickets.map((r) => r.id));
const apiUserMemberIds = new Set<number>(
apiUsers
.map((r) => r.cwMemberId)
.filter((v): v is number => Number.isInteger(v))
);
console.log(
`[diag] API sets: notes=${apiNoteIds.size} tickets=${apiTicketIds.size} usersWithCwMemberId=${apiUserMemberIds.size}`
);
const cwTotal = await cwPrisma.ticketNote.count();
const apiTotal = apiNoteIds.size;
let missingSrServiceRecId = 0;
let missingMemberRecId = 0;
let missingParentTicketInApi = 0;
let missingAuthorMappingInApi = 0;
let eligibleForSync = 0;
let eligibleButMissingInApi = 0;
let automateTotal = 0;
let automateEligibleForSync = 0;
let automateMissingSrServiceRecId = 0;
let automateMissingMemberRecId = 0;
let automateMissingParentTicketInApi = 0;
let automateMissingAuthorMappingInApi = 0;
let automateEligibleButMissingInApi = 0;
const sampleMissingParentTicketIds: number[] = [];
const sampleMissingAuthorMemberRecIds: number[] = [];
const sampleEligibleButMissingNoteIds: number[] = [];
const automateSampleMemberRecIds: number[] = [];
const automateSampleNoteIdsMissingInApi: number[] = [];
const missingAuthorCounts = new Map<number, number>();
const missingParentCounts = new Map<number, number>();
let cursor = 0;
const batchSize = 5000;
console.log(
`[diag] Scanning CW TicketNote rows in batches of ${batchSize}...`
);
while (true) {
const batch = await cwPrisma.ticketNote.findMany({
where: {
ticketNoteRecId: {
gt: cursor,
},
},
orderBy: {
ticketNoteRecId: "asc",
},
select: {
ticketNoteRecId: true,
srServiceRecId: true,
memberRecId: true,
createdBy: true,
originalAuthor: true,
},
take: batchSize,
});
if (batch.length === 0) break;
for (const row of batch) {
const noteId = row.ticketNoteRecId;
const srServiceRecId = row.srServiceRecId;
const memberRecId = row.memberRecId;
const isAutomate = isAutomateApiAuthor(
row.createdBy,
row.originalAuthor
);
if (isAutomate) {
automateTotal++;
if (
memberRecId &&
automateSampleMemberRecIds.length < 20 &&
!automateSampleMemberRecIds.includes(memberRecId)
) {
automateSampleMemberRecIds.push(memberRecId);
}
}
let blocked = false;
if (!srServiceRecId) {
missingSrServiceRecId++;
if (isAutomate) {
automateMissingSrServiceRecId++;
}
blocked = true;
} else if (!apiTicketIds.has(srServiceRecId)) {
missingParentTicketInApi++;
if (isAutomate) {
automateMissingParentTicketInApi++;
}
blocked = true;
missingParentCounts.set(
srServiceRecId,
(missingParentCounts.get(srServiceRecId) ?? 0) + 1
);
if (sampleMissingParentTicketIds.length < 20) {
sampleMissingParentTicketIds.push(srServiceRecId);
}
}
if (!memberRecId) {
missingMemberRecId++;
if (isAutomate) {
automateMissingMemberRecId++;
}
blocked = true;
} else if (!apiUserMemberIds.has(memberRecId)) {
missingAuthorMappingInApi++;
if (isAutomate) {
automateMissingAuthorMappingInApi++;
}
blocked = true;
missingAuthorCounts.set(
memberRecId,
(missingAuthorCounts.get(memberRecId) ?? 0) + 1
);
if (sampleMissingAuthorMemberRecIds.length < 20) {
sampleMissingAuthorMemberRecIds.push(memberRecId);
}
}
if (!blocked) {
eligibleForSync++;
if (isAutomate) {
automateEligibleForSync++;
}
if (!apiNoteIds.has(noteId)) {
eligibleButMissingInApi++;
if (isAutomate) {
automateEligibleButMissingInApi++;
if (automateSampleNoteIdsMissingInApi.length < 20) {
automateSampleNoteIdsMissingInApi.push(noteId);
}
}
if (sampleEligibleButMissingNoteIds.length < 50) {
sampleEligibleButMissingNoteIds.push(noteId);
}
}
}
}
cursor = batch[batch.length - 1]!.ticketNoteRecId;
if (cursor % 50000 < batchSize) {
console.log(`[diag] Progress cursor=${cursor}`);
}
}
const summary: Summary = {
cwTotal,
apiTotal,
eligibleForSync,
missingSrServiceRecId,
missingMemberRecId,
missingParentTicketInApi,
missingAuthorMappingInApi,
eligibleButMissingInApi,
sampleMissingParentTicketIds,
sampleMissingAuthorMemberRecIds,
sampleEligibleButMissingNoteIds,
topMissingAuthorMemberRecIds: [...missingAuthorCounts.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, 20)
.map(([memberRecId, count]) => ({ memberRecId, count })),
topMissingParentTicketIds: [...missingParentCounts.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, 20)
.map(([srServiceRecId, count]) => ({ srServiceRecId, count })),
automateApi: {
total: automateTotal,
eligibleForSync: automateEligibleForSync,
missingSrServiceRecId: automateMissingSrServiceRecId,
missingMemberRecId: automateMissingMemberRecId,
missingParentTicketInApi: automateMissingParentTicketInApi,
missingAuthorMappingInApi: automateMissingAuthorMappingInApi,
eligibleButMissingInApi: automateEligibleButMissingInApi,
sampleMemberRecIds: automateSampleMemberRecIds,
sampleNoteIdsMissingInApi: automateSampleNoteIdsMissingInApi,
},
};
console.log("[diag] TicketNote sync gap summary:");
console.log(JSON.stringify(summary, null, 2));
} finally {
await Promise.all([cwPrisma.$disconnect(), apiPrisma.$disconnect()]);
}
};
main().catch((error) => {
console.error("[diag] Failed:", error);
process.exit(1);
});