database->first('SELECT COUNT(*) AS total FROM job'); return (int) ($row['total'] ?? 0); } /** @return list> */ public function allWithDetails(): array { return $this->database->query( 'SELECT j.id, j.campaign_id, j.job_type_id, j.attribute_values, j.created_at, j.updated_at, ct.name AS campaign_type_name, jt.name AS job_type_name, jt.attributes AS job_type_attributes FROM job j INNER JOIN campaign c ON j.campaign_id = c.id INNER JOIN campaign_type ct ON c.campaign_type_id = ct.id INNER JOIN job_type jt ON j.job_type_id = jt.id ORDER BY j.id DESC' ); } /** @return list> */ public function allWithDetailsForCampaign(int $campaignId): array { return $this->database->query( 'SELECT j.id, j.campaign_id, j.job_type_id, j.attribute_values, j.created_at, j.updated_at, ct.name AS campaign_type_name, jt.name AS job_type_name, jt.attributes AS job_type_attributes FROM job j INNER JOIN campaign c ON j.campaign_id = c.id INNER JOIN campaign_type ct ON c.campaign_type_id = ct.id INNER JOIN job_type jt ON j.job_type_id = jt.id WHERE j.campaign_id = :campaign_id ORDER BY j.id DESC', ['campaign_id' => $campaignId] ); } public function findWithDetails(int $id): ?array { return $this->database->first( 'SELECT j.id, j.campaign_id, j.job_type_id, j.attribute_values, j.created_at, j.updated_at, ct.name AS campaign_type_name, jt.name AS job_type_name, jt.attributes AS job_type_attributes FROM job j INNER JOIN campaign c ON j.campaign_id = c.id INNER JOIN campaign_type ct ON c.campaign_type_id = ct.id INNER JOIN job_type jt ON j.job_type_id = jt.id WHERE j.id = :id', ['id' => $id] ); } /** Used after INSERT to recover the generated id for audit logging. */ public function findLatestByCampaignAndType(int $campaignId, int $jobTypeId): ?array { return $this->database->first( 'SELECT TOP (1) * FROM job WHERE campaign_id = :campaign_id AND job_type_id = :job_type_id ORDER BY id DESC', ['campaign_id' => $campaignId, 'job_type_id' => $jobTypeId] ); } public function create(Job $job): bool { return $this->database->execute( 'INSERT INTO job (campaign_id, job_type_id, attribute_values) VALUES (:campaign_id, :job_type_id, :attribute_values)', [ 'campaign_id' => $job->campaignId, 'job_type_id' => $job->jobTypeId, 'attribute_values' => json_encode($job->attributeValues, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE), ] ); } public function update(Job $job): bool { return $this->database->execute( 'UPDATE job SET campaign_id = :campaign_id, job_type_id = :job_type_id, attribute_values = :attribute_values, updated_at = CURRENT_TIMESTAMP WHERE id = :id', [ 'campaign_id' => $job->campaignId, 'job_type_id' => $job->jobTypeId, 'attribute_values' => json_encode($job->attributeValues, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE), 'id' => $job->id, ] ); } }