Skip to content

Commit 783dc11

Browse files
Added update capabilities to database. Changed id to ROWID in all instances (#11)
1 parent 04d1031 commit 783dc11

File tree

5 files changed

+311
-33
lines changed

5 files changed

+311
-33
lines changed

server/src/database-controller.ts

Lines changed: 211 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { open, Database } from "sqlite";
33
import { DataTable } from "./interfaces/database-interface";
44
import { resolve } from "path";
55
import { rejects } from "assert";
6-
import { GetQuery, TableData, RadData } from "./types";
6+
import { GetQuery, TableData, InsertData, UpdateData } from "./types";
77
import { error } from "console";
88

99
export class DatabaseController {
@@ -68,6 +68,29 @@ export class DatabaseController {
6868
`);
6969
}
7070

71+
// Will probably remove, decided to change id to ROWID to add efficiency
72+
private async initializeViews(): Promise<void> {
73+
const paperView = `CREATE VIEW paper_view AS
74+
SELECT
75+
ROWID AS id,
76+
year,
77+
paper_name,
78+
part_no,
79+
type,
80+
manufacturer,
81+
data_type,
82+
testing_location,
83+
testing_type
84+
FROM paper`;
85+
await this.db.run(paperView, (err: any) => {
86+
if (err) {
87+
console.error(`Error creating paper view: ${err}`);
88+
} else {
89+
console.log("View created successfully.");
90+
}
91+
});
92+
}
93+
7194
/*
7295
* Parameters:
7396
* - tableName (string): the name of the table to check
@@ -99,15 +122,15 @@ export class DatabaseController {
99122
* created in the 'author_paper_join' table for each author.
100123
* Returns: None
101124
*/
102-
async insertPaper(paperData: TableData): Promise<void> {
125+
async insertPaper(paperData: InsertData): Promise<void> {
103126
if (!this.db) {
104127
throw new Error(`Database not initialized`);
105128
}
106129
try {
107130
const paperId = await this.createPaper(paperData);
108131
console.log(paperData.author);
109132
for (const author in paperData.author) {
110-
const authorRowId = await this.getOrCreateAuthor(
133+
const authorRowId = await this.getOrCreateAuthorByName(
111134
paperData.author[author],
112135
);
113136
await this.linkPaperToAuthor(authorRowId, paperId);
@@ -120,14 +143,36 @@ export class DatabaseController {
120143
}
121144
}
122145

146+
/*
147+
* !!! NOTE !!!!
148+
* paperData MUST contain the ROWID of the paper for proper update purposes.
149+
*
150+
* Parameters:
151+
* - paperData: Data to be updated coresponding to a sepcific paper
152+
* Function: Updates an entry for the given paper in the 'paper' table and
153+
* entries in the 'author' and 'author_paper_join' are updated.
154+
* Returns: None
155+
*/
156+
async updatePaper(paperData: UpdateData): Promise<void> {
157+
if (!this.db) {
158+
throw new Error(`Database not initialized`);
159+
}
160+
try {
161+
await this.updatePaperTable(paperData);
162+
if (paperData.author) {
163+
await this.syncPaperAuthors(paperData.ROWID, paperData.author);
164+
}
165+
} catch (error) {}
166+
}
167+
123168
/*
124169
* Parameters:
125170
* - paperData: An insertData instance
126171
* Function: Uses the given data to create an entry in the table cotaining the papers
127172
* Returns:
128173
* - number: The ROWID of the paper.
129174
*/
130-
private async createPaper(paperData: TableData): Promise<number> {
175+
private async createPaper(paperData: InsertData): Promise<number> {
131176
if (!this.db) {
132177
throw new Error(`Database not initialized`);
133178
}
@@ -165,6 +210,34 @@ export class DatabaseController {
165210
}
166211
}
167212

213+
private async updatePaperTable(paperData: UpdateData): Promise<void> {
214+
let query = `UPDATE paper SET `;
215+
let conditions: string[] = [];
216+
const params: string[] = [];
217+
if (!this.db) {
218+
throw new Error(`Database not initialized`);
219+
}
220+
try {
221+
for (const [key, value] of Object.entries(paperData)) {
222+
if (
223+
value !== undefined &&
224+
value !== null &&
225+
key !== "author" &&
226+
key !== "ROWID"
227+
) {
228+
conditions.push(`${key} = ?`);
229+
params.push(`${value}`);
230+
}
231+
}
232+
params.push(`${paperData.ROWID}`);
233+
query += `${conditions.join(",")} WHERE ROWID = ?`;
234+
await this.db.run(query, params);
235+
} catch (error) {
236+
console.error(error);
237+
throw error;
238+
}
239+
}
240+
168241
/*
169242
* Parameters:
170243
* - author: the name of the author to be added/retrieved
@@ -173,7 +246,7 @@ export class DatabaseController {
173246
* Returns:
174247
* - number: The ROWID of the author.
175248
*/
176-
private async getOrCreateAuthor(author: string): Promise<number> {
249+
private async getOrCreateAuthorByName(author: string): Promise<number> {
177250
if (!this.db) {
178251
throw new Error(`Database not initialized`);
179252
}
@@ -197,6 +270,100 @@ export class DatabaseController {
197270
}
198271
}
199272

273+
/*
274+
* Parameters:
275+
* - authors: List of authors given when update is passed
276+
* - paperId: Id of the paper to update
277+
* Function: Compares the new list of authors to the current links, if it is
278+
* found that a preexisting link should no longer exist, it is removed.
279+
* If a new link is needed, it is created.
280+
* Returns: None
281+
*/
282+
private async syncPaperAuthors(
283+
paperId: number,
284+
authors: string[],
285+
): Promise<void> {
286+
if (!this.db) {
287+
throw new Error(`Database not initialized`);
288+
}
289+
290+
try {
291+
// Begin transaction for consistency
292+
await this.db.exec("BEGIN TRANSACTION");
293+
294+
// Retrieve the current authors linked to the paper
295+
const currentAuthors = await this.db.all<
296+
{ author_id: number; name: string }[]
297+
>(
298+
`
299+
SELECT a.name
300+
FROM paper_author_join paj
301+
INNER JOIN author a ON paj.author_id = a.ROWID
302+
WHERE paj.paper_id = ?
303+
`,
304+
[paperId],
305+
);
306+
307+
// Extract names of current authors
308+
const currentAuthorNames = currentAuthors.map((author) => author.name);
309+
310+
// Identify authors to add
311+
const authorsToAdd = authors.filter(
312+
(author) => !currentAuthorNames.includes(author),
313+
);
314+
315+
// Identify authors to remove
316+
const authorsToRemove = currentAuthorNames.filter(
317+
(author) => !authors.includes(author),
318+
);
319+
320+
// Add new author links
321+
for (const authorName of authorsToAdd) {
322+
// Ensure the author exists in the `author` table
323+
const row = await this.db.get<{ ROWID: number }>(
324+
`
325+
INSERT OR IGNORE INTO author (name) VALUES (?);
326+
SELECT ROWID FROM author WHERE name = ?;
327+
`,
328+
[authorName, authorName],
329+
);
330+
331+
if (!row || typeof row.ROWID !== "number") {
332+
throw new Error(`Failed to retrieve ROWID for author: ${authorName}`);
333+
}
334+
// Link the author to the paper using the retrieved ROWID
335+
await this.db.run(
336+
`
337+
INSERT INTO paper_author_join (paper_id, author_id) VALUES (?, ?)
338+
`,
339+
[paperId, row.ROWID],
340+
);
341+
}
342+
343+
// Remove unwanted author links
344+
for (const authorName of authorsToRemove) {
345+
await this.db.run(
346+
`
347+
DELETE FROM paper_author_join
348+
WHERE paper_id = ?
349+
AND author_id = (SELECT ROWID FROM author WHERE name = ?)
350+
`,
351+
[paperId, authorName],
352+
);
353+
}
354+
355+
// Commit the transaction
356+
await this.db.exec("COMMIT");
357+
} catch (error) {
358+
// Rollback the transaction on error
359+
await this.db.exec("ROLLBACK");
360+
console.error(
361+
`Failed to sync authors for paperID: ${paperId}\nError: ${error}`,
362+
);
363+
throw error;
364+
}
365+
}
366+
200367
/*
201368
* Parameters:
202369
* - authorId: The ROWID of the author to link
@@ -212,8 +379,12 @@ export class DatabaseController {
212379
): Promise<void> {
213380
try {
214381
await this.db.run(
215-
"INSERT INTO paper_author_join (paper_id, author_id) VALUES (?, ?)",
216-
[paperId, authorId],
382+
`INSERT INTO paper_author_join (paper_id, author_id)
383+
SELECT ?, ?
384+
WHERE NOT EXISTS (
385+
SELECT 1 FROM paper_author_join WHERE paper_id = ? AND author_id = ?
386+
)`,
387+
[paperId, authorId, paperId, authorId],
217388
);
218389
} catch (error) {
219390
console.error(
@@ -223,6 +394,35 @@ export class DatabaseController {
223394
}
224395
}
225396

397+
/*
398+
* Parameters:
399+
* - authorId: The ROWID of the author to check
400+
* - paperId: The ROWID of the paper to checl
401+
* Function: Checks for the existence of an entry in author_paper_join table.
402+
* This
403+
* Returns: None
404+
*/
405+
private async checkPaperToAuthorLink(
406+
authorId: number,
407+
paperId: number,
408+
): Promise<boolean> {
409+
if (!this.db) {
410+
throw new Error(`Database not initialized`);
411+
}
412+
try {
413+
const row = await this.db.get(
414+
"SELECT * FROM paper_author_join WHERE paper_id = ? AND author_id = ?",
415+
[paperId, authorId],
416+
);
417+
return !!row; // Return true if a row is found, otherwise false
418+
} catch (error) {
419+
console.error(
420+
`Problem retrieving paper-author link for authorID: ${authorId}, paperID: ${paperId}\n Error: ${error}`,
421+
);
422+
throw error;
423+
}
424+
}
425+
226426
/*
227427
* Parameters: None
228428
* Function: Gets the total number of papers in the table 'paper'
@@ -262,7 +462,6 @@ export class DatabaseController {
262462
let query = `
263463
SELECT
264464
p.*,
265-
p.ROWID AS id,
266465
GROUP_CONCAT(a.name, ', ') AS author
267466
FROM
268467
paper p
@@ -278,7 +477,6 @@ export class DatabaseController {
278477

279478
return new Promise<TableData[]>(async (resolve, reject) => {
280479
try {
281-
282480
const result = await this.db.all(query, `${search}%`);
283481
console.log("Query executed successfully:");
284482

@@ -296,22 +494,15 @@ export class DatabaseController {
296494
});
297495
}
298496

299-
async getFilteredData(queryData: GetQuery): Promise<RadData[]> {
497+
async getFilteredData(queryData: GetQuery): Promise<TableData[]> {
300498
if (!this.db) {
301499
throw new Error("Database not initialized");
302500
}
303501

304502
// Base SELECT query
305503
let query = `
306504
SELECT
307-
p.year,
308-
p.paper_name,
309-
p.part_no,
310-
p.type,
311-
p.manufacturer,
312-
p.data_type,
313-
p.testing_location,
314-
p.testing_type,
505+
p.*,
315506
GROUP_CONCAT(a.name, ', ') AS author
316507
FROM
317508
paper p
@@ -354,13 +545,13 @@ export class DatabaseController {
354545

355546
console.log(query);
356547

357-
return new Promise<RadData[]>(async (resolve, reject) => {
548+
return new Promise<TableData[]>(async (resolve, reject) => {
358549
try {
359550
const result = await this.db.all(query, params);
360551
console.log("Query executed successfully:");
361552

362553
// Map rows to RadData format
363-
const radData: RadData[] = result.map((row) => ({
554+
const radData: TableData[] = result.map((row) => ({
364555
...row,
365556
author: row.author ? row.author.split(", ") : [],
366557
}));

server/src/routes/cascade-router.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import express, { Request, Response, Router } from "express";
22
import { DatabaseController } from "../database-controller";
3-
import { GetQuery, RadData, Testing } from "../types";
3+
import { GetQuery, TableData, Testing } from "../types";
44
import authenticateJWT from "../auth/jwt-auth";
55

66

@@ -30,7 +30,7 @@ export default function cascadeRouter(
3030
router.post("/tableRequest", (req: Request, res: Response) => {
3131
try {
3232
getFilteredRows(requestFromJSON(req.body), dbController).then(
33-
(result: RadData[]) => {
33+
(result: TableData[]) => {
3434
res.send(responseToJSON(result));
3535
},
3636
);
@@ -45,14 +45,14 @@ export default function cascadeRouter(
4545
function getFilteredRows(
4646
getData: GetQuery,
4747
dbcontroller: DatabaseController,
48-
): Promise<RadData[]> {
48+
): Promise<TableData[]> {
4949
return dbcontroller.getFilteredData(getData);
5050
}
5151

5252
function requestFromJSON(body: any) {
5353
return body as GetQuery;
5454
}
5555

56-
function responseToJSON(radDataArray: RadData[]): string {
56+
function responseToJSON(radDataArray: TableData[]): string {
5757
return JSON.stringify(radDataArray, null, 2); // null and 2 prettify the JSON
5858
}

0 commit comments

Comments
 (0)