All files / plainweb/src/admin/database/routes/[table] edit.tsx

0% Statements 0/89
0% Branches 0/1
0% Functions 0/1
0% Lines 0/89

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113                                                                                                                                                                                                                                 
import { type Column, columnType, renderValue } from "admin/column";
import { config } from "admin/config";
import { TableRow } from "admin/database/routes/[table]/components/table-row";
import { sql } from "drizzle-orm";
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
import type { Handler } from "handler";
 
export const POST: Handler = async ({ req, res }) => {
  const tableName = req.params.table as string;
  const db = res.locals.database as BetterSQLite3Database<
    Record<string, unknown>
  >;
  const { __row, ...updatedData } = req.body;
 
  const columns = db.all<Column>(
    sql`SELECT * FROM pragma_table_info(${tableName})`,
  );
 
  const newData: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(updatedData)) {
    const column = columns.find((column) => column.name === key);
    if (!column) {
      throw new Error(`Column ${key} not found in table ${tableName}`);
    }
    newData[key] = value;
    if (column.type === "INTEGER") {
      newData[key] = Number.parseInt(value as string);
    } else if (column.type === "REAL") {
      newData[key] = Number.parseFloat(value as string);
    }
  }
 
  config.verbose >= 1 ||
    console.log("[admin] [database]", "saving row", newData);
  const oldRow = JSON.parse(__row as string);
 
  const setClause = Object.entries(newData)
    .map(([column, value]) => sql`${sql.identifier(column)} = ${value}`)
    .reduce((acc, curr) => sql`${acc}, ${curr}`);
 
  const whereClause = Object.entries(oldRow)
    .map(([column, value]) => sql`${sql.identifier(column)} = ${value}`)
    .reduce((acc, curr) => sql`${acc} AND ${curr}`);
 
  db.run(
    sql`UPDATE ${sql.identifier(tableName)} SET ${setClause} WHERE ${whereClause}`,
  );
 
  config.verbose >= 1 || console.log("[admin] [database]", "row saved");
 
  return <TableRow tableName={tableName} columns={columns} row={newData} />;
};
 
function estimateNrOfRows(value: string) {
  return String(Math.max(Math.round(String(value).length / 30), 1));
}
 
export const GET: Handler = async ({ req, res }) => {
  const tableName = req.params.table as string;
  const rowData = JSON.parse(decodeURIComponent(req.query.row as string));
  const db = res.locals.database as BetterSQLite3Database;
 
  const columns = db.all<Column>(
    sql`SELECT * FROM pragma_table_info(${tableName})`,
  );
 
  return (
    <tr>
      <td class="w-16 flex items-center justify-center">
        <button
          class="btn btn-xs btn-primary"
          type="submit"
          hx-post={`${config.adminBasePath}/database/${tableName}/edit`}
          hx-include="closest tr"
        >
          Save
        </button>
        <input type="hidden" name="__row" value={JSON.stringify(rowData)} />
      </td>
      {columns.map((column) => {
        const tsType = columnType(column.type);
        const value = rowData[column.name];
        const safeFormattedValue = renderValue(value, tsType);
        return (
          <td
            data-type={tsType}
            class="border border-neutral px-2 py-1 max-w-32 relative"
          >
            {safeFormattedValue}
            <textarea
              class="top-0 left-0 w-full py-1 pl-2 m-0 bg-base-200 absolute"
              rows={estimateNrOfRows(value)}
              name={column.name}
              safe
            >
              {value}
            </textarea>
          </td>
        );
      })}
      <td>
        <button
          class="btn btn-xs ml-1"
          type="reset"
          hx-get={`${config.adminBasePath}/database/${tableName}/row?row=${encodeURIComponent(JSON.stringify(rowData))}`}
        >
          Cancel
        </button>
      </td>
    </tr>
  );
};