Skip to content

Commit 6bb98a6

Browse files
authored
Merge pull request #9 from JerryImMouse/each-route
Route to process each extra record and delete fields
2 parents 487741b + a203906 commit 6bb98a6

File tree

5 files changed

+96
-0
lines changed

5 files changed

+96
-0
lines changed

src/database/generic.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,17 @@ export class RecordExtra implements IRecordExtra {
238238
return new RecordExtra(db, res.record_id, res.json, res.id);
239239
}
240240

241+
public static async findAll<T extends IDatabase>(db: T): Promise<RecordExtra[]> {
242+
const res = await db.selectAll<IRecordExtra>(RecordExtra._tableName);
243+
244+
const resObjects: RecordExtra[] = [];
245+
res?.forEach(obj => {
246+
resObjects.push(new RecordExtra(db, obj.record_id, obj.json, obj.id))
247+
})
248+
249+
return resObjects;
250+
}
251+
241252
public static async create<T extends IDatabase>(db: T, record_id: number, json: string): Promise<RecordExtra> {
242253
const recordExists = await db.select<IRecordExtra>(RecordExtra._tableName, 'record_id', record_id);
243254

src/database/postgres.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ export class PostgresDatabase implements IDatabase {
124124
return this.selectOrOnly(table, {[key]: value});
125125
}
126126

127+
public selectAll<T>(table: string): Promise<T[] | null> {
128+
return this.selectOrOnly(table, {});
129+
}
130+
127131
public async selectOrOnly<T>(table: string, data: Record<string, string | number>): Promise<T | null> {
128132
const columns = Object.keys(data);
129133
const values = Object.values(data);
@@ -145,6 +149,27 @@ export class PostgresDatabase implements IDatabase {
145149
}
146150
}
147151

152+
public async selectOr<T>(table: string, data: Record<string, string | number>): Promise<T[] | null> {
153+
const columns = Object.keys(data);
154+
const values = Object.values(data);
155+
156+
const conditions = columns.map((column, idx) => `${column} = $${idx + 1}`).join(" OR ");
157+
const query = columns.length !== 0 ? `SELECT * FROM ${table} WHERE ${conditions}` : `SELECT * FROM ${table};`;
158+
159+
try {
160+
const result = await this._connection.query(query, values);
161+
162+
if (result.rows.length > 0) {
163+
return result.rows as T[];
164+
}
165+
166+
return null;
167+
} catch (err) {
168+
this._handleError(query, err);
169+
return null;
170+
}
171+
}
172+
148173
public async selectLimitOffsetLike<T>(
149174
table: string,
150175
offset: number,

src/database/sqlite.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ export class SqliteDatabase implements IDatabase {
135135
return this.selectOrOnly(table, {[key]: value});
136136
}
137137

138+
public selectAll<T>(table: string): Promise<T[] | null> {
139+
return this.selectOr(table, {});
140+
}
141+
138142
public selectOrOnly<T>(table: string, data: Record<string, string | number>): Promise<T | null> {
139143
const columns = Object.keys(data);
140144
const values = Object.values(data);
@@ -154,6 +158,25 @@ export class SqliteDatabase implements IDatabase {
154158
})
155159
}
156160

161+
public selectOr<T>(table: string, data: Record<string, string | number>): Promise<T[] | null> {
162+
const columns = Object.keys(data);
163+
const values = Object.values(data);
164+
165+
const conditions = columns.map(column => `${column} = ?`).join(" OR ");
166+
const query = columns.length !== 0 ? `SELECT * FROM ${table} WHERE ${conditions}` : `SELECT * FROM ${table};`;
167+
168+
return new Promise((resolve, reject) => {
169+
this._connection.all(query, values, (err, rows) => {
170+
if (!this._handleError(query, err)) {
171+
reject(false);
172+
return;
173+
}
174+
175+
resolve(rows ? rows as T[] : null);
176+
})
177+
})
178+
}
179+
157180
// i really don't like how I called it, but.. okay
158181
public selectLimitOffsetLike<T>(
159182
table: string,

src/types/database.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ export interface IDatabase {
22
init(): Promise<boolean>;
33
execute(sql: string, params: (string | number)[]): Promise<boolean>;
44
select<T>(table: string, key: string, value: string | number): Promise<T | null>;
5+
selectAll<T>(table: string): Promise<T[] | null>;
56
selectLimitOffsetLike<T>(table: string, offset: number, limit: number, data: Record<string, string | number> | undefined = undefined): Promise<T[] | null>;
67
selectOrOnly<T>(table: string, data: Record<string, string | number>): Promise<T | null>
8+
selectOr<T>(table: string, data: Record<string, string | number>): Promise<T[] | null>
79
upsert(table: string, data: Record<string, string | number>): Promise<number | null>;
810

911
delete(table: string, key: string, value: string | number): Promise<boolean>;

src/web/controllers/api.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { findRecordByBody, findRecordByQuery, validateToken } from '../middlewar
44
import { WebHelpers } from '../helpers';
55
import { RecordExtendedRequest } from '../../types/web';
66
import { Database, RecordExtra } from '../../database/generic';
7+
import { Logger } from '../../logging';
78

89
const apiStuff = [checkApiToken, findRecordByQuery, validateToken];
910
const dbImpl = Database.getDbImpl();
11+
const log = Logger.get();
1012

1113
/// Here is the format
1214
/// getMETHODNAME - GET /api/METHODNAME
@@ -20,6 +22,9 @@ export class ApiController {
2022
router.get('/extra', [checkApiToken, findRecordByQuery], this.getExtraData);
2123
router.patch('/extra', [checkApiToken, findRecordByQuery], this.patchExtraData);
2224
router.post('/delete', [checkApiToken, findRecordByBody], this.postDelete);
25+
26+
router.delete('/each/extra', [checkApiToken], this.deleteEachExtraData);
27+
2328
router.get('/link', this.getLink);
2429
return router;
2530
}
@@ -74,6 +79,7 @@ export class ApiController {
7479
}
7580

7681
res.status(200).contentType('application/json').send(record.extra.json); // manually set content-type because our `json` field is a json str already
82+
log.debug(`Returned extra data for ${record.discord_uid}`, JSON.parse(record.extra.json));
7783
}
7884

7985
public static async patchExtraData(req: RecordExtendedRequest, res: Response) {
@@ -91,6 +97,35 @@ export class ApiController {
9197
record.extra.json = merged;
9298

9399
await record.extra.save();
100+
101+
res.status(200).send();
102+
log.debug(`Set extra data for ${record.discord_uid}`, JSON.parse(record.extra.json));
103+
}
104+
105+
public static async deleteEachExtraData(req: Request, res: Response) {
106+
const fields = req.body['fields'] as string[] | undefined;
107+
if (!fields) {
108+
res.status(400).json({error: "Fields is not supplied"});
109+
return;
110+
}
111+
112+
const allRecords = await RecordExtra.findAll(dbImpl);
113+
114+
for (const record of allRecords) {
115+
try {
116+
const jsonData = JSON.parse(record.json);
117+
118+
fields.forEach(field => {
119+
delete jsonData[field];
120+
});
121+
122+
record.json = JSON.stringify(jsonData);
123+
await record.save();
124+
} catch (error) {
125+
console.error("Failed to process record:", error);
126+
}
127+
}
128+
94129
res.status(200).send();
95130
}
96131

0 commit comments

Comments
 (0)