Files
avante-movil/src/sync/mutations.ts
T

164 lines
4.1 KiB
TypeScript
Raw Normal View History

/**
* Mutaciones de alto nivel. Cada una:
* 1. (updates) escribe optimistamente en la BD local para reflejar el cambio ya,
* 2. encola la operación en el outbox para enviarla cuando haya red.
*
* El servidor SIEMPRE fija user_id/reported_by/project_id y valida permisos:
* el cliente nunca los envía (ver brief §5.1).
*/
import { getDb } from '../db/database';
import { enqueueOperation } from '../db/outbox';
import {
IssuePriority,
IssueStatus,
IssueType,
} from '../api/types';
// ----- progress (append-only en servidor) -----
export function recordProgressUpdate(input: {
phase_id: number;
progress: number;
comment?: string;
location?: { lat: number; lng: number };
}): Promise<string> {
return enqueueOperation('progress_update', 'create', { ...input });
}
// ----- feature.update (editable, last-write-wins) -----
export async function updateFeature(input: {
id: number;
status?: string;
progress?: number;
responsible?: string;
}): Promise<string> {
const db = await getDb();
const sets: string[] = [];
const params: unknown[] = [];
if (input.status !== undefined) {
sets.push('status = ?');
params.push(input.status);
}
if (input.progress !== undefined) {
sets.push('progress = ?');
params.push(input.progress);
}
if (input.responsible !== undefined) {
sets.push('responsible = ?');
params.push(input.responsible);
}
if (sets.length) {
params.push(input.id);
await db.runAsync(
`UPDATE features SET ${sets.join(', ')}, dirty = 1 WHERE id = ?`,
...(params as never[]),
);
}
return enqueueOperation('feature', 'update', { ...input });
}
// ----- inspection.create (append-only) -----
export function createInspection(input: {
feature_id: number;
template_id?: number;
data?: Record<string, unknown>;
status?: string;
result?: string;
notes?: string;
}): Promise<string> {
return enqueueOperation('inspection', 'create', { ...input });
}
// ----- issues -----
export function createIssue(input: {
project_id: number;
feature_id?: number;
title: string;
description?: string;
priority?: IssuePriority;
status?: IssueStatus;
type?: IssueType;
}): Promise<string> {
return enqueueOperation('issue', 'create', { ...input });
}
export async function updateIssue(input: {
id: number;
title?: string;
description?: string;
priority?: IssuePriority;
status?: IssueStatus;
type?: IssueType;
assigned_to?: number;
resolution_notes?: string;
}): Promise<string> {
const db = await getDb();
const cols: Record<string, unknown> = {
title: input.title,
description: input.description,
priority: input.priority,
status: input.status,
type: input.type,
assigned_to: input.assigned_to,
resolution_notes: input.resolution_notes,
};
const sets: string[] = [];
const params: unknown[] = [];
for (const [k, v] of Object.entries(cols)) {
if (v !== undefined) {
sets.push(`${k} = ?`);
params.push(v);
}
}
if (sets.length) {
params.push(input.id);
await db.runAsync(
`UPDATE issues SET ${sets.join(', ')}, dirty = 1 WHERE id = ?`,
...(params as never[]),
);
}
return enqueueOperation('issue', 'update', { ...input });
}
// ----- issue tasks -----
export function createIssueTask(input: {
issue_id: number;
title: string;
assigned_to?: number;
due_date?: string;
is_done?: boolean;
}): Promise<string> {
return enqueueOperation('issue_task', 'create', { ...input });
}
export async function updateIssueTask(input: {
id: number;
title?: string;
assigned_to?: number;
due_date?: string;
is_done?: boolean;
}): Promise<string> {
const db = await getDb();
if (input.is_done !== undefined) {
await db.runAsync(
'UPDATE issue_tasks SET is_done = ?, dirty = 1 WHERE id = ?',
input.is_done ? 1 : 0,
input.id,
);
}
return enqueueOperation('issue_task', 'update', { ...input });
}
// ----- issue comments (append-only) -----
export function createIssueComment(input: {
issue_id: number;
body: string;
}): Promise<string> {
return enqueueOperation('issue_comment', 'create', { ...input });
}