- Move the Tauri app (React frontend + Rust backend) into desktop/ via git mv — configs unchanged (relative paths: tauri.conf.json, vite.config.ts) - Root package.json becomes a private bun workspace container with orchestration scripts; desktop package renamed gridline-desktop - Scaffold www/ with Astro 7 + Tailwind v4 (hand-wired vite plugin, static output, ready for Dokploy) - Update release.yml for the new layout: projectPath: desktop, desktop/src-tauri resource paths, rust-cache workspace path - Update README + AGENTS.md structure trees and dev commands - Verified: vitest (1074), cargo test (354), desktop build, tauri dev (window launches), tauri build (dmg + app bundles), Astro build
98 lines
3.5 KiB
TypeScript
98 lines
3.5 KiB
TypeScript
import type { QueueItem } from "../stores/dbViewerStore";
|
|
|
|
/**
|
|
* Payload emitted for a single queued change, keyed to match the Rust
|
|
* `Change` enum variants (snake_case). Sent to `executeChange`.
|
|
*/
|
|
export type ChangePayload = Record<string, unknown>;
|
|
|
|
function j(v: unknown): string {
|
|
return JSON.stringify(v ?? {});
|
|
}
|
|
|
|
function q(s: string): string {
|
|
return `"${s.replace(/"/g, '""')}"`;
|
|
}
|
|
|
|
function lit(v: unknown): string {
|
|
if (v === null || v === undefined) return "NULL";
|
|
if (typeof v === "boolean") return v ? "TRUE" : "FALSE";
|
|
if (typeof v === "number") return String(v);
|
|
if (typeof v === "string") return `'${v.replace(/'/g, "''")}'`;
|
|
return `'${JSON.stringify(v).replace(/'/g, "''")}'`;
|
|
}
|
|
|
|
function tableRef(schema: string | undefined, table: string | undefined): string {
|
|
if (!table) return "-";
|
|
return schema ? `${q(schema)}.${q(table)}` : q(table);
|
|
}
|
|
|
|
export function buildChangeSql(item: QueueItem): string {
|
|
const t = tableRef(item.schema, item.table);
|
|
switch (item.type) {
|
|
case "insert": {
|
|
const data = item.newData ?? {};
|
|
const cols = Object.keys(data);
|
|
return `INSERT INTO ${t} (${cols.map(q).join(", ")}) VALUES (${cols.map((c) => lit(data[c])).join(", ")})`;
|
|
}
|
|
case "update": {
|
|
const data = item.newData ?? {};
|
|
const pk = item.primaryKey ?? {};
|
|
const setClause = Object.keys(data).map((c) => `${q(c)} = ${lit(data[c])}`).join(", ");
|
|
const whereClause = Object.keys(pk).map((c) => `${q(c)} = ${lit(pk[c])}`).join(" AND ");
|
|
return `UPDATE ${t} SET ${setClause} WHERE ${whereClause}`;
|
|
}
|
|
case "delete": {
|
|
const pk = item.primaryKey ?? {};
|
|
const whereClause = Object.keys(pk).map((c) => `${q(c)} = ${lit(pk[c])}`).join(" AND ");
|
|
return `DELETE FROM ${t} WHERE ${whereClause}`;
|
|
}
|
|
case "bulk_insert": {
|
|
const cols = item.columns ?? [];
|
|
const rows = item.rows ?? [];
|
|
const valueRows = rows
|
|
.map((row) => `(${row.map(lit).join(", ")})`)
|
|
.join(", ");
|
|
return `INSERT INTO ${t} (${cols.map(q).join(", ")}) VALUES ${valueRows}`;
|
|
}
|
|
case "empty_table":
|
|
return `DELETE FROM ${t}`;
|
|
case "ddl":
|
|
return item.sql ?? "";
|
|
case "rebuild_table":
|
|
return item.sql ?? "";
|
|
case "drop_table":
|
|
return `DROP TABLE ${t}`;
|
|
default:
|
|
return item.sql ?? "";
|
|
}
|
|
}
|
|
|
|
export function buildChangePayload(item: QueueItem): ChangePayload {
|
|
const schema = item.schema ?? "";
|
|
const table = item.table ?? "";
|
|
switch (item.type) {
|
|
case "insert":
|
|
return { id: item.id, type: "insert", schema, table, data: j(item.newData) };
|
|
case "update":
|
|
return { id: item.id, type: "update", schema, table,
|
|
primary_key: j(item.primaryKey), old_data: j(item.oldData), new_data: j(item.newData) };
|
|
case "delete":
|
|
return { id: item.id, type: "delete", schema, table, primary_key: j(item.primaryKey) };
|
|
case "alter_table":
|
|
return { id: item.id, type: "alter_table", schema, table, sql: item.sql, rollback_sql: "" };
|
|
case "bulk_insert":
|
|
return { id: item.id, type: "bulk_insert", schema, table,
|
|
columns: item.columns ?? [], rows: item.rows ?? [] };
|
|
case "drop_table":
|
|
return { id: item.id, type: "drop_table", schema, table };
|
|
case "empty_table":
|
|
return { id: item.id, type: "empty_table", schema, table };
|
|
case "ddl":
|
|
return { id: item.id, type: "ddl", sql: item.sql };
|
|
case "rebuild_table":
|
|
return { id: item.id, type: "rebuild_table", sql: item.sql };
|
|
default:
|
|
return { id: item.id, type: item.type, sql: item.sql };
|
|
}
|
|
} |