Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

174 lines
6.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Analyse the per-route query dumps and classify each query.
*/
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = dirname(fileURLToPath(import.meta.url));
function classify(sql, params) {
const s = sql.replace(/\s+/g, " ").trim();
// Migrations / system
if (/pragma_table_info/i.test(s)) return "pragma_table_info";
if (/sqlite_master/i.test(s)) return "sqlite_master";
if (/PRAGMA/i.test(s)) return "pragma";
if (/from "kysely_migration"/i.test(s)) return "migrations_check";
if (/from "_emdash_migrations_lock"/i.test(s)) return "migrations_lock";
if (/from "_emdash_migrations"/i.test(s)) return "migrations_check";
if (/from "_emdash_collections"/i.test(s)) return "schema_collections";
if (/from "_emdash_fields"/i.test(s)) return "schema_fields";
if (/from "_emdash_setup_state"/i.test(s)) return "setup_check";
if (/from "_plugin_state"/i.test(s)) return "plugin_state";
if (/from "_emdash_cron_tasks"/i.test(s) || /_emdash_cron_tasks SET/i.test(s))
return "cron_recovery";
if (/_emdash_404_log/i.test(s)) return "404_log_migration";
if (/alter table/i.test(s)) return "ddl_alter";
if (/create table/i.test(s)) return "ddl_create";
if (/create.*index/i.test(s)) return "ddl_index";
if (/drop index/i.test(s)) return "ddl_drop_index";
if (/insert into "_emdash_migrations"/i.test(s)) return "migrations_record";
if (/delete from "options"/i.test(s)) return "options_delete";
if (/SELECT name FROM sqlite_master/i.test(s)) return "fts_table_check";
// Auth
if (/from "_emdash_sessions"/i.test(s)) return "auth_session";
if (/from "_emdash_users"/i.test(s)) return "auth_user_lookup";
if (/from "_emdash_passkeys"/i.test(s)) return "auth_passkey";
// Settings/options
if (/from "options"/i.test(s) && /LIKE/i.test(s)) {
const p0 = params?.[0];
if (typeof p0 === "string") return `options_prefix:${p0}`;
return "options_prefix";
}
if (/from "options"/i.test(s) && /"name" in/i.test(s)) {
return "options_in";
}
if (/from "options"/i.test(s) && /"name" = \?/i.test(s)) {
const p0 = params?.[0];
if (typeof p0 === "string") return `option:${p0}`;
return "option:single";
}
if (/from "options"/i.test(s)) return "option:other";
// Menus / widgets
if (/from "_emdash_menus"/i.test(s)) return "menu_lookup";
if (/from "_emdash_menu_items"/i.test(s)) return "menu_items";
if (/from "_emdash_widget_areas"/i.test(s)) {
const p0 = params?.[0];
return `widget_area:${p0 ?? ""}`;
}
if (/from "_emdash_widgets"/i.test(s)) return "widget";
// Bylines
if (/from "_emdash_content_bylines"/i.test(s)) return "byline_hydration";
if (/from "_emdash_bylines"/i.test(s)) return "byline_lookup";
// Taxonomies
if (/from "_emdash_taxonomy_defs"/i.test(s)) return "taxonomy_defs";
if (/from "content_taxonomies"/i.test(s) && /count\(/i.test(s)) return "taxonomy_counts";
if (/from "content_taxonomies"/i.test(s)) return "taxonomy_for_entries";
if (/from "taxonomies"/i.test(s)) return "taxonomy_terms";
// Author lookup (id, author_id)
if (/SELECT id, author_id FROM "ec_/i.test(s)) return "author_id_lookup";
// Content tables
const ecMatch = s.match(/from "ec_([a-z_]+)"/i) || s.match(/FROM "ec_([a-z_]+)"/);
if (ecMatch) {
const coll = ecMatch[1];
// detail vs list
if (/slug = \?/i.test(s) && /id = \?/i.test(s)) return `entry_by_slug:${coll}`;
if (/where "id" = \?/i.test(s)) return `entry_by_id:${coll}`;
if (/LIMIT \?/i.test(s)) return `collection_list:${coll}`;
if (/ORDER BY/i.test(s)) return `collection_list:${coll}`;
return `collection_other:${coll}`;
}
// Media
if (/from "_emdash_media"/i.test(s)) return "media_lookup";
// Plugins / pages dispatch
if (/from "_emdash_plugin/i.test(s)) return "plugin_lookup";
// SEO redirects
if (/from "_emdash_redirects"/i.test(s)) return "redirects";
// Comments
if (/from "_emdash_comments"/i.test(s)) return "comments";
// Default
return "other";
}
const targetArg = process.argv[2] || "sqlite";
const dir = resolve(__dirname, targetArg);
const files = readdirSync(dir).filter((f) => f.endsWith(".json") && f !== "_all.json");
// per-route classification table
const tables = {}; // { routePhase: { className: count } }
const allByClass = {}; // { className: count }
const totalDuration = {}; // { className: ms }
const routeOrder = [
"root",
"posts",
"posts_building_for_the_long_term",
"pages_about",
"category_development",
"tag_webdev",
"rss_xml",
"search",
];
const phases = ["cold", "warm"];
for (const f of files) {
const path = resolve(dir, f);
const events = JSON.parse(readFileSync(path, "utf8"));
const key = f.replace(/\.json$/, "");
tables[key] = {};
for (const e of events) {
const cls = classify(e.sql, e.params);
tables[key][cls] = (tables[key][cls] || 0) + 1;
allByClass[cls] = (allByClass[cls] || 0) + 1;
totalDuration[cls] = (totalDuration[cls] || 0) + (e.durationMs || 0);
}
}
// print table: rows = classes, cols = route.phase
const headerRoutes = [];
for (const r of routeOrder) for (const p of phases) headerRoutes.push(`${r}.${p}`);
const allClasses = Object.keys(allByClass).toSorted(
(a, b) => (allByClass[b] || 0) - (allByClass[a] || 0),
);
let out = `# Query classification (${targetArg})\n\n`;
out += `Total events: ${Object.values(allByClass).reduce((a, b) => a + b, 0)}\n\n`;
out += `## Top classes by total count\n\n`;
out += `| class | count | total_ms |\n|---|---:|---:|\n`;
for (const c of allClasses.slice(0, 20)) {
out += `| ${c} | ${allByClass[c]} | ${totalDuration[c].toFixed(2)} |\n`;
}
out += "\n";
out += `## Per-route × phase classification\n\n`;
out += `| class |`;
for (const h of headerRoutes) out += ` ${h} |`;
out += ` total |\n|---|`;
for (const _ of headerRoutes) out += "---:|";
out += "---:|\n";
for (const c of allClasses) {
out += `| ${c} |`;
let total = 0;
for (const h of headerRoutes) {
const v = tables[h]?.[c] || 0;
total += v;
out += ` ${v || ""} |`;
}
out += ` ${total} |\n`;
}
out += "\n";
out += `## Per-route totals\n\n`;
out += `| route.phase | count |\n|---|---:|\n`;
for (const h of headerRoutes) {
const total = Object.values(tables[h] || {}).reduce((a, b) => a + b, 0);
out += `| ${h} | ${total} |\n`;
}
writeFileSync(resolve(__dirname, `classification.${targetArg}.md`), out);
process.stdout.write(out);