refactor(server): dedupe shard-state shaping, upsert builder, and config DB models
All checks were successful
PR Checks / bot-install (pull_request) Successful in 18s
PR Checks / client-build (pull_request) Successful in 26s
PR Checks / server-tests (pull_request) Successful in 11m4s

Address the SonarQube copy-paste findings that reflect real duplication (as
opposed to the intentional cross-package / admin-player mirror copies, which
are by-design and left as-is):

- shardState.model.js: listOnline() re-inlined the exact field mapping that
  shapeOnline() already provides (used by listOnlineLinked). Collapse it onto
  shapeOnline so the two can no longer drift.
- shardState.db.js: extract a single upsertRow(table, pkCol, pk, fields,
  {coalesce}) builder for the five near-identical INSERT ... ON DUPLICATE KEY
  UPDATE bodies (online/houses/champs/guilds/governors). shard_online keeps its
  COALESCE-on-NULL semantics via the coalesce flag.
- botConfig/emailConfig/uoLinkConfig .db.js: generate get()/upsert() from a
  shared singletonConfigDb(table, cols) factory instead of three byte-identical
  copies.

Behavior unchanged; full server suite (381 tests) passes.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-21 12:35:39 -05:00
parent 9b0f2d93d8
commit 401db8f75c
6 changed files with 75 additions and 155 deletions

View File

@@ -0,0 +1,35 @@
const { query } = require('../utils/db')
// Factory for the singleton config tables (bot_config, email_config,
// uo_link_config). Each is a one-row table keyed on id = 1: `get()` returns the
// row (or null before the admin first saves it), and `upsert()` writes only the
// columns the model prepared, leaving the rest untouched. The three tables share
// this shape exactly, so the DB layer is generated rather than copy-pasted —
// only the table name and column list differ.
//
// `fields` are already prepared by the model (secrets pre-encrypted); ordering
// and encryption stay a model-layer concern.
function singletonConfigDb(table, cols) {
async function get() {
const rows = await query(`SELECT ${cols} FROM ${table} WHERE id = 1 LIMIT 1`)
return rows[0] || null
}
async function upsert(fields) {
const columns = Object.keys(fields)
const vals = columns.map((c) => fields[c])
const insertCols = ['id', ...columns].map((c) => `\`${c}\``).join(', ')
const placeholders = ['1', ...columns.map(() => '?')].join(', ')
const updates = columns.map((c) => `\`${c}\` = VALUES(\`${c}\`)`).join(', ')
await query(
`INSERT INTO ${table} (${insertCols}) VALUES (${placeholders})
ON DUPLICATE KEY UPDATE ${updates}`,
vals,
)
return get()
}
return { get, upsert }
}
module.exports = singletonConfigDb