-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
361 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Request, Response } from "express"; | ||
|
||
import { createTableEntity } from "../services/createTableEntity.js"; | ||
import { CreateTableEntityParams } from "../types/openapi.js"; | ||
|
||
/** | ||
* Update a specific entity | ||
* @param req | ||
* @param res | ||
*/ | ||
export default async function ( | ||
req: Request<CreateTableEntityParams, null, Record<string, string>, unknown>, | ||
res: Response<string>, | ||
) { | ||
try { | ||
const result: string = await createTableEntity(req.body, req.params); | ||
res.status(200).contentType("text/html").send(result); | ||
} catch (error) { | ||
console.error(error); | ||
res.sendStatus(500); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Request, Response } from "express"; | ||
|
||
import { deleteTableEntity } from "../services/deleteTableEntity.js"; | ||
import { | ||
DeleteTableEntityParams, | ||
DeleteTableEntityQuery, | ||
} from "../types/openapi.js"; | ||
|
||
/** | ||
* Update a specific entity | ||
* @param req | ||
* @param res | ||
*/ | ||
export default async function ( | ||
req: Request< | ||
DeleteTableEntityParams, | ||
null, | ||
Record<string, string>, | ||
DeleteTableEntityQuery | ||
>, | ||
res: Response<string>, | ||
) { | ||
try { | ||
const result: string = await deleteTableEntity( | ||
req.params, | ||
req.query, | ||
); | ||
res.status(200).contentType("text/html").send(result); | ||
} catch (error) { | ||
console.error(error); | ||
res.sendStatus(500); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Request, Response } from "express"; | ||
|
||
import { getTableUpdateEntityPage } from "../services/getTableUpdateEntityPage.js"; | ||
import { GetTableEntityParams, GetTableEntityQuery } from "../types/openapi.js"; | ||
|
||
/** | ||
* Retrieve a specific entity | ||
* @param req | ||
* @param res | ||
*/ | ||
export default async function ( | ||
req: Request<GetTableEntityParams, null, unknown, GetTableEntityQuery>, | ||
res: Response<string>, | ||
) { | ||
try { | ||
const result: string = await getTableUpdateEntityPage( | ||
req.params, | ||
req.query, | ||
); | ||
res.status(200).contentType("text/html").send(result); | ||
} catch (error) { | ||
console.error(error); | ||
res.sendStatus(500); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,21 @@ | ||
import express from "express"; | ||
|
||
import routeGetTableEntities from "./controllers/getTableEntities.js"; | ||
import routeGetTableEntity from "./controllers/getTableEntity.js"; | ||
import routeGetTables from "./controllers/getTables.js"; | ||
import routeCreateTableEntity from "./controllers/createTableEntity.js"; | ||
import routeDeleteTableEntity from "./controllers/deleteTableEntity.js"; | ||
import routeGetTableCreateEntityPage from "./controllers/getTableCreateEntityPage.js"; | ||
import routeGetTableEntitiesPage from "./controllers/getTableEntitiesPage.js"; | ||
import routeGetTablesPage from "./controllers/getTablesPage.js"; | ||
import routeGetTableUpdateEntityPage from "./controllers/getTableUpdateEntityPage.js"; | ||
import routeUpdateTableEntity from "./controllers/updateTableEntity.js"; | ||
|
||
const router = express.Router(); | ||
|
||
router.get("/tables/:tableName", routeGetTableEntities); | ||
router.get("/tables/:tableName/entity", routeGetTableEntity); | ||
router.get("/", routeGetTables); | ||
router.post("/tables/:tableName/entity", routeUpdateTableEntity); | ||
router.get("/tables/:tableName", routeGetTableEntitiesPage); | ||
router.get("/tables/:tableName/create", routeGetTableCreateEntityPage); | ||
router.get("/tables/:tableName/update", routeGetTableUpdateEntityPage); | ||
router.get("/", routeGetTablesPage); | ||
router.post("/tables/:tableName/create", routeCreateTableEntity); | ||
router.post("/tables/:tableName/update", routeUpdateTableEntity); | ||
router.post("/tables/:tableName/delete", routeDeleteTableEntity); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import knex from "../config/database.js"; | ||
import { CreateTableEntityParams } from "../types/openapi.js"; | ||
import { getHtmlPageTemplate } from "../utils/html.js"; | ||
|
||
/** | ||
* Create a new entity | ||
* @param request | ||
* @param params | ||
*/ | ||
export async function createTableEntity( | ||
request: Record<string, string>, | ||
params: CreateTableEntityParams, | ||
): Promise<string> { | ||
const { tableName } = params; | ||
const dataToInsert = request; | ||
|
||
if (!tableName) { | ||
throw new Error("Table name is required"); | ||
} | ||
|
||
try { | ||
const insertedId = await knex(tableName).insert(dataToInsert); | ||
|
||
const entityCreatedData: string[] = []; | ||
Object.keys(dataToInsert).forEach((key) => { | ||
entityCreatedData.push(key + ": <b>" + dataToInsert[key] + "</b>"); | ||
}); | ||
|
||
const formHtml = ` | ||
<div> | ||
<p><a href="/">Back to tables</a></p> | ||
<p><a href="/tables/${tableName}">Back to table '${tableName}'</a></p> | ||
</div> | ||
<div> | ||
<p>The entity has been created successfully:</p> | ||
<ul>${entityCreatedData.map((value) => "<li>" + value + "</li>").join("")}</ul> | ||
<p>Inserted ID: ${insertedId}</p> | ||
</div> | ||
`; | ||
|
||
return getHtmlPageTemplate( | ||
`Entity in table '${params.tableName}'`, | ||
formHtml, | ||
); | ||
} catch (error) { | ||
console.error("Error creating entity:", error); | ||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import knex from "../config/database.js"; | ||
import { | ||
DeleteTableEntityParams, | ||
DeleteTableEntityQuery, | ||
} from "../types/openapi.js"; | ||
import { getHtmlPageTemplate } from "../utils/html.js"; | ||
|
||
/** | ||
* Delete a specific entity | ||
* @param params | ||
* @param query | ||
*/ | ||
export async function deleteTableEntity( | ||
params: DeleteTableEntityParams, | ||
query: DeleteTableEntityQuery, | ||
): Promise<string> { | ||
const { tableName } = params; | ||
const primaryKeys = query; | ||
|
||
if (!tableName) { | ||
throw new Error("Table name is required"); | ||
} | ||
|
||
try { | ||
const deletedRows = await knex(tableName) | ||
.where(primaryKeys) | ||
.del(); | ||
|
||
if (deletedRows === 0) { | ||
throw new Error("No rows deleted"); | ||
} | ||
|
||
const entityId: string[] = []; | ||
Object.keys(primaryKeys).forEach((primaryKey) => { | ||
entityId.push(primaryKey + " " + primaryKeys[primaryKey]); | ||
}); | ||
|
||
const formHtml = ` | ||
<div> | ||
<p><a href="/">Back to tables</a></p> | ||
<p><a href="/tables/${tableName}">Back to table '${tableName}'</a></p> | ||
</div> | ||
<div> | ||
<p>The entity has been deleted successfully:</p> | ||
<p>Entity ID: ${entityId.join(", ")}</p> | ||
</div> | ||
`; | ||
|
||
return getHtmlPageTemplate( | ||
`Entity '${entityId.join(", ")}' in table '${params.tableName}'`, | ||
formHtml, | ||
); | ||
} catch (error) { | ||
console.error("Error deleting entity:", error); | ||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import knex from "../config/database.js"; | ||
import { GetTableEntityParams } from "../types/openapi.js"; | ||
import { getColumns, tableCheck } from "../utils/db.js"; | ||
import { getHtmlPageTemplate } from "../utils/html.js"; | ||
|
||
/** | ||
* Create a new entity | ||
* @param params | ||
*/ | ||
export async function getTableCreateEntityPage( | ||
params: GetTableEntityParams, | ||
): Promise<string> { | ||
const { tableName } = params; | ||
|
||
const tableColumns = await tableCheck(tableName); | ||
|
||
const columns = await getColumns(knex, tableName || "table"); | ||
|
||
if (!columns) { | ||
throw new Error("no such columns"); | ||
} | ||
|
||
const autoIncrementColumns = columns | ||
.filter((value) => value.Extra === "auto_increment") | ||
.map((value) => value.Field); | ||
|
||
const visibleColumns = columns | ||
.filter( | ||
(value) => value.Key === "PRI" || tableColumns.includes(value.Field), | ||
) | ||
.map((value) => value.Field); | ||
|
||
const formHtml = ` | ||
<div> | ||
<p><a href="/">Back to tables</a></p> | ||
<p><a href="/tables/${tableName}">Back to table '${tableName}'</a></p> | ||
</div> | ||
<div> | ||
<form action="/tables/${tableName}/create" method="post"> | ||
${visibleColumns | ||
.filter((column) => tableColumns.includes(column)) | ||
.map((column) => { | ||
const columnType = columns.find((c) => c.Field === column)?.Type; | ||
let inputType = "text"; | ||
let inputAttributes = ""; | ||
let inputElement = ""; | ||
if (columnType == null) { | ||
inputType = "text"; | ||
} else if ( | ||
columnType.includes("int") || | ||
columnType.includes("tinyint") | ||
) { | ||
inputType = "number"; | ||
} else if ( | ||
columnType.includes("datetime") || | ||
columnType.includes("timestamp") | ||
) { | ||
inputType = "datetime-local"; | ||
inputAttributes = `value="${new Date().toISOString().slice(0, 16)}"`; | ||
inputElement = ` | ||
<input type="${inputType}" id="${column}" name="${column}" ${inputAttributes} ${autoIncrementColumns.includes(column) ? "disabled" : ""}> | ||
`; | ||
} else if (columnType.includes("enum")) { | ||
const enumValues = columnType | ||
.replace("enum(", "") | ||
.replace(")", "") | ||
.split(","); | ||
inputAttributes = `value="${enumValues[0]}"`; | ||
inputElement = ` | ||
<select id="${column}" name="${column}" ${autoIncrementColumns.includes(column) ? "disabled" : ""}> | ||
${enumValues.map((value) => `<option value="${value}" ${value === enumValues[0] ? "selected" : ""}>${value}</option>`).join("")} | ||
</select> | ||
`; | ||
} else if (columnType.includes("bool")) { | ||
inputType = "checkbox"; | ||
inputAttributes = `value="1"`; | ||
} else { | ||
inputElement = ` | ||
<input type="${inputType}" id="${column}" name="${column}" value="" autocomplete="off" ${autoIncrementColumns.includes(column) ? "disabled" : ""} ${inputAttributes}> | ||
`; | ||
} | ||
if (!inputElement) { | ||
inputElement = ` | ||
<input type="${inputType}" id="${column}" name="${column}" autocomplete="off" ${autoIncrementColumns.includes(column) ? "disabled" : ""} ${inputAttributes}> | ||
`; | ||
} | ||
return ` | ||
<div> | ||
<p><label for="${column}">${column} - ${columnType}</label></p> | ||
${inputElement} | ||
</div> | ||
`; | ||
}) | ||
.join("")} | ||
<button type="submit">Create</button> | ||
</form> | ||
</div> | ||
`; | ||
|
||
return getHtmlPageTemplate( | ||
`Create new entity in table '${params.tableName}'`, | ||
formHtml, | ||
); | ||
} |
Oops, something went wrong.