Runrepository
**Site relevance:** Spiralist.org
**Memory type:** plugin source memory
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Domain/RunRepository.php
**Size:** 5.7 KB
Summary
namespace SpiralistWorkspace\Domain;
Source Preview
This source file is short enough to preview directly on its source-memory page.
<?php
namespace SpiralistWorkspace\Domain;
use SpiralistWorkspace\Installer;
if (!defined('ABSPATH')) {
exit;
}
/**
* Persists prompt run history.
*/
class RunRepository
{
/**
* Creates a pending run.
*/
public function create(array $data): int
{
global $wpdb;
$wpdb->insert(
Installer::table('prompt_runs'),
[
'prompt_post_id' => (int) ($data['prompt_post_id'] ?? 0),
'user_id' => (int) ($data['user_id'] ?? 0),
'conversation_id' => !empty($data['conversation_id']) ? (int) $data['conversation_id'] : null,
'version_number_used' => max(1, (int) ($data['version_number_used'] ?? 1)),
'model_used' => sanitize_text_field((string) ($data['model_used'] ?? '')),
'request_payload_json' => wp_json_encode((array) ($data['request_payload_json'] ?? []), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'response_payload_json' => null,
'input_text' => (string) ($data['input_text'] ?? ''),
'output_text' => null,
'status' => sanitize_key((string) ($data['status'] ?? 'queued')),
'created_utc' => gmdate('Y-m-d H:i:s'),
'completed_utc' => null,
'cost_estimate' => 0,
'token_usage_json' => null,
'error_message' => null,
'openai_response_id' => null,
],
['%d', '%d', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%f', '%s', '%s', '%s']
);
return (int) $wpdb->insert_id;
}
/**
* Marks a run complete.
*/
public function complete(int $run_id, array $result): void
{
global $wpdb;
$wpdb->update(
Installer::table('prompt_runs'),
[
'response_payload_json' => wp_json_encode((array) ($result['response_payload_json'] ?? []), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'output_text' => (string) ($result['output_text'] ?? ''),
'status' => sanitize_key((string) ($result['status'] ?? 'completed')),
'completed_utc' => gmdate('Y-m-d H:i:s'),
'cost_estimate' => (float) ($result['cost_estimate'] ?? 0),
'token_usage_json' => wp_json_encode((array) ($result['token_usage_json'] ?? []), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
'error_message' => !empty($result['error_message']) ? sanitize_textarea_field((string) $result['error_message']) : null,
'openai_response_id' => !empty($result['openai_response_id']) ? sanitize_text_field((string) $result['openai_response_id']) : null,
],
[
'id' => $run_id,
],
['%s', '%s', '%s', '%s', '%f', '%s', '%s', '%s'],
['%d']
);
}
/**
* Retrieves a single run.
*/
public function get(int $run_id): array
{
global $wpdb;
$sql = $wpdb->prepare(
'SELECT * FROM ' . Installer::table('prompt_runs') . ' WHERE id = %d LIMIT 1',
$run_id
);
$row = $wpdb->get_row($sql, ARRAY_A);
return is_array($row) ? $row : [];
}
/**
* Lists runs for a user.
*/
public function list_for_user(int $user_id, int $limit = 20): array
{
global $wpdb;
$sql = $wpdb->prepare(
'SELECT * FROM ' . Installer::table('prompt_runs') . ' WHERE user_id = %d ORDER BY created_utc DESC LIMIT %d',
$user_id,
max(1, $limit)
);
$rows = $wpdb->get_results($sql, ARRAY_A);
return is_array($rows) ? $rows : [];
}
/**
* Lists runs for a prompt.
*/
public function list_for_prompt(int $prompt_id, int $limit = 20): array
{
global $wpdb;
$sql = $wpdb->prepare(
'SELECT * FROM ' . Installer::table('prompt_runs') . ' WHERE prompt_post_id = %d ORDER BY created_utc DESC LIMIT %d',
$prompt_id,
max(1, $limit)
);
$rows = $wpdb->get_results($sql, ARRAY_A);
return is_array($rows) ? $rows : [];
}
/**
* Returns prompt IDs ordered by completed run count.
*
* @return array<int,array{prompt_post_id:int,run_count:int,last_run_utc:string}>
*/
public function top_prompt_stats(int $limit = 10): array
{
global $wpdb;
$sql = $wpdb->prepare(
'SELECT prompt_post_id, COUNT(*) AS run_count, MAX(created_utc) AS last_run_utc FROM ' . Installer::table('prompt_runs') . " WHERE status = 'completed' GROUP BY prompt_post_id ORDER BY run_count DESC, last_run_utc DESC LIMIT %d",
max(1, $limit)
);
$rows = $wpdb->get_results($sql, ARRAY_A);
if (!is_array($rows)) {
return [];
}
return array_map(
static fn(array $row): array => [
'prompt_post_id' => (int) ($row['prompt_post_id'] ?? 0),
'run_count' => (int) ($row['run_count'] ?? 0),
'last_run_utc' => (string) ($row['last_run_utc'] ?? ''),
],
$rows
);
}
/**
* Counts runs since midnight UTC for the user.
*/
public function count_for_today(int $user_id): int
{
global $wpdb;
$sql = $wpdb->prepare(
'SELECT COUNT(*) FROM ' . Installer::table('prompt_runs') . ' WHERE user_id = %d AND created_utc >= %s',
$user_id,
gmdate('Y-m-d 00:00:00')
);
return (int) $wpdb->get_var($sql);
}
}