query(empty($params) ? $sql : $wpdb->prepare($sql, $params)); if ($result === false) { self::fail($wpdb->last_error ?: 'Query failed'); } return (int) $result; } public static function get_row(string $sql, array $params = [], string $output = OBJECT): object|array|null { global $wpdb; $query = empty($params) ? $sql : $wpdb->prepare($sql, $params); $row = $wpdb->get_row($query, $output); self::throw_if_error(); return $row; } public static function get_results(string $sql, array $params = [], string $output = OBJECT): array { global $wpdb; $rows = $wpdb->get_results(empty($params) ? $sql : $wpdb->prepare($sql, $params), $output); self::throw_if_error(); return $rows ?? []; } public static function get_var(string $sql, array $params = []): ?string { global $wpdb; $value = $wpdb->get_var(empty($params) ? $sql : $wpdb->prepare($sql, $params)); self::throw_if_error(); return $value; } public static function get_col(string $sql, array $params = []): array { global $wpdb; $col = $wpdb->get_col(empty($params) ? $sql : $wpdb->prepare($sql, $params)); self::throw_if_error(); return $col ?? []; } public static function insert(string $table, array $data, array|string|null $format = null): int { global $wpdb; $result = $wpdb->insert($table, $data, $format); if ($result === false) { self::fail($wpdb->last_error ?: 'Insert failed'); } return (int) $wpdb->insert_id; } public static function update(string $table, array $data, array $where, array|string|null $format = null, array|string|null $where_format = null): int { global $wpdb; $result = $wpdb->update($table, $data, $where, $format, $where_format); if ($result === false) { self::fail($wpdb->last_error ?: 'Update failed'); } return (int) $result; } public static function delete(string $table, array $where, array|string|null $where_format = null): int { global $wpdb; $result = $wpdb->delete($table, $where, $where_format); if ($result === false) { self::fail($wpdb->last_error ?: 'Delete failed'); } return (int) $result; } public static function begin_transaction(): void { global $wpdb; $wpdb->query('START TRANSACTION'); } public static function commit(): void { global $wpdb; $wpdb->query('COMMIT'); } public static function rollback(): void { global $wpdb; $wpdb->query('ROLLBACK'); } /** * Acquire a named MySQL advisory lock (GET_LOCK). Session-scoped and * independent of transactions, so callers must release it explicitly. * Returns true if the lock was obtained within $timeout seconds. */ public static function acquire_lock(string $name, int $timeout = 10): bool { global $wpdb; return (int) $wpdb->get_var($wpdb->prepare('SELECT GET_LOCK(%s, %d)', $name, $timeout)) === 1; } public static function release_lock(string $name): void { global $wpdb; $wpdb->query($wpdb->prepare('SELECT RELEASE_LOCK(%s)', $name)); } public static function prefix(): string { global $wpdb; return $wpdb->prefix; } public static function last_insert_id(): int { global $wpdb; return (int) $wpdb->insert_id; } public static function charset_collate(): string { global $wpdb; return $wpdb->get_charset_collate(); } private static function throw_if_error(): void { global $wpdb; if ($wpdb->last_error) { self::fail($wpdb->last_error); } } private static function fail(string $message): void { Logger::error('[Db] ' . $message); throw new DbException($message); } }