Add new methods to writeHandler, modify dbHandler, locality write works, now_ls works

This commit is contained in:
ShootingStar91
2024-08-25 15:50:53 +03:00
parent 1c70a3df65
commit f32d78071c
5 changed files with 87 additions and 66 deletions
+12 -11
View File
@@ -2,10 +2,10 @@ import { Request, Router } from 'express'
import { getAllLocalities, getLocalityDetails, validateEntireLocality } from '../services/locality'
import { fixBigInt } from '../utils/common'
import { EditDataType, EditMetaData, LocalityDetailsType } from '../../../frontend/src/backendTypes'
import { write } from '../services/write/write'
import { requireOneOf } from '../middlewares/authorizer'
import { Role } from '../../../frontend/src/types'
import { deleteLocality } from '../services/write/delete'
import { writeLocality } from '../services/write/locality'
const router = Router()
@@ -35,16 +35,17 @@ router.put(
if (validationErrors.length > 0) {
return res.status(400).send({ validationErrors })
}
const result = await write(
editedLocality,
'now_loc',
req.user!.initials,
comment ?? '',
editedLocality.lid ? 'update' : 'add',
references ?? []
)
return res.status(200).send(result ? { id: result } : { error: 'error' })
const result = await writeLocality(editedLocality)
return res.status(200).send({ id: result })
// const result = await write(
// editedLocality,
// 'now_loc',
// req.user!.initials,
// comment ?? '',
// editedLocality.lid ? 'update' : 'add',
// references ?? []
// )
// return res.status(200).send(result ? { id: result } : { error: 'error' })
}
)
+21 -35
View File
@@ -1,46 +1,32 @@
import {
EditDataType,
LocalityDetailsType,
LocalitySpeciesDetailsType,
SpeciesDetailsType,
} from '../../../../frontend/src/backendTypes'
import { EditDataType, LocalityDetailsType } from '../../../../frontend/src/backendTypes'
import { NOW_DB_NAME } from '../../utils/config'
import { WriteHandler } from '../writeOperations/writeHandler'
import { DbValue } from './writeUtils'
export const writeLocality = async (locality: EditDataType<LocalityDetailsType>) => {
const writeHandler = new WriteHandler(NOW_DB_NAME, 'now_loc')
const writeHandler = new WriteHandler(NOW_DB_NAME, 'now_loc', 'lid')
await writeHandler.start()
for (const ls of locality.now_ls) {
if (ls.rowState === 'new') {
await writeLocalitySpecies(writeHandler, ls)
} else if (ls.rowState === 'removed') {
await deleteLocalitySpecies(writeHandler, ls.lid!, ls.species_id!)
}
if (!locality.lid) {
const { lid: newLid } = await writeHandler.createObject('now_loc', locality, ['lid'])
locality.lid = newLid as number
}
}
/* Writes now_ls entries, and also any new species inside. */
const writeLocalitySpecies = async (
writeHandler: WriteHandler,
localitySpecies: EditDataType<LocalitySpeciesDetailsType>
) => {
let species_id: DbValue | undefined = localitySpecies.com_species!.species_id
if (!localitySpecies.species_id) {
species_id = await writeSpecies(writeHandler, localitySpecies.com_species!)
writeHandler.idValue = locality.lid
/* Write possible new species of now_ls, and save those id's to now_ls objects */
for (const localitySpecies of locality.now_ls) {
const species = localitySpecies.com_species!
if (species.species_id) continue
const { species_id } = await writeHandler.createObject('com_species', species, ['species_id'])
species.species_id = species_id as number
}
if (species_id) localitySpecies.com_species!.species_id = species_id
return await writeHandler.createObject('now_ls', localitySpecies, ['lid', 'species_id'])
}
const writeSpecies = async (writeHandler: WriteHandler, species: EditDataType<SpeciesDetailsType>) => {
const { species_id } = await writeHandler.createObject('com_species', species, ['species_id'])
return species_id as number
}
await writeHandler.upsertList('now_ls', locality.now_ls, ['lid', 'species_id'])
await writeHandler.upsertList('now_mus', locality.now_mus, ['lid', 'museum'])
await writeHandler.upsertList('now_ss', locality.now_ss, ['lid', 'sed_struct'])
await writeHandler.upsertList('now_coll_meth', locality.now_coll_meth, ['lid', 'coll_meth'])
await writeHandler.upsertList('now_syn_loc', locality.now_syn_loc, ['lid', 'syn_id'])
const deleteLocalitySpecies = async (writeHandler: WriteHandler, lid: number, species_id: number) => {
return await writeHandler.delete('now_ls', [
{ column: 'lid', value: lid },
{ column: 'species_id', value: species_id },
])
await writeHandler.end()
return locality.lid
}
@@ -31,11 +31,11 @@ export class DatabaseHandler {
async insert<T>(table: AllowedTables, items: DbWriteItem[], returnColumns?: string[]) {
const returnString = returnColumns ? `RETURNING ${returnColumns.join(', ')}` : ''
const { columns, values } = this.getValuesAndColumns(items)
return await this.executeQuery<T>(`INSERT INTO ${this.dbName}.${table} (?) VALUES (?) ${returnString}`, [
columns,
values,
])
const returnValue = await this.executeQuery<T>(
`INSERT INTO ${this.dbName}.${table} (${columns.join(', ')}) VALUES (${values.map(() => '?').join(', ')}) ${returnString}`,
values
)
return (returnValue as T[])[0]
}
async update(table: AllowedTables, items: DbWriteItem[], ids: DbWriteItem[]) {
@@ -46,8 +46,8 @@ export class DatabaseHandler {
const whereClause = createWhereClause(idColumns)
await this.executeQuery(`UPDATE ${this.dbName}.${table} (${columnsString}) WHERE ${whereClause}`, [
values,
idValues,
...values,
...idValues,
])
}
@@ -58,7 +58,7 @@ export class DatabaseHandler {
const returningClause = returnColumns?.join(' ,') ?? `${idColumns.join(', ')}`
return await this.executeQuery(
`DELETE FROM ${this.dbName}.${table} WHERE ${whereClause} RETURNING ${returningClause}`,
[idValues]
idValues
)
}
@@ -66,16 +66,22 @@ export class DatabaseHandler {
const columnsString = columns.length === 0 ? '*' : columns.map(col => `${this.dbName}.${col}`).join(', ')
const { columns: idColumns, values: idValues } = this.getValuesAndColumns(ids)
const whereClause = createWhereClause(idColumns)
return await this.executeQuery<T>(`SELECT ${columnsString} FROM ${this.dbName}.${table} WHERE ${whereClause}`, [
idValues,
])
return await this.executeQuery<T>(
`SELECT ${columnsString} FROM ${this.dbName}.${table} WHERE ${whereClause}`,
idValues
)
}
async executeQuery<T>(query: string, values?: Array<DbValue[]>) {
async executeQuery<T>(query: string, values?: Array<DbValue>) {
if (!this.connection) throw new Error('DB connection not initialized')
logger.info(`Executing SQL query: ${query}`)
return await this.connection.query<T>(query, values)
logger.info(`Executing SQL query: ${query} \nWith values ${JSON.stringify(values)}\n`)
let returnValue
if (values) {
returnValue = await this.connection.query<T>(query, values)
} else {
returnValue = await this.connection.query<T>(query)
}
return returnValue
}
}
@@ -14,13 +14,14 @@ export const valueIsDifferent = (newValue: unknown, oldValue: unknown) => {
return true
}
/* Takes in an object and returns only the non-object fields with their field name (column) and value */
export const getItemList = (object: Record<string, unknown>) => {
export const getItemList = (object: Record<string, unknown>, skipEmptyValues?: boolean) => {
const list: DbWriteItem[] = Object.entries(object)
.map(([field, value]) => ({
column: field,
value: value as DbValue,
}))
.filter(item => typeof item.value === 'object')
.filter(item => typeof item.value !== 'object')
.filter(item => item.column !== 'rowState')
if (skipEmptyValues) return list.filter(item => item.value !== '')
return list
}
@@ -1,15 +1,20 @@
import { RowState } from '../../../../frontend/src/backendTypes'
import { AllowedTables, DbValue, PrimaryTables, WriteItem } from '../write/writeUtils'
import { DatabaseHandler, DbWriteItem } from './databaseHandler'
import { getItemList, valueIsDifferent } from './utils'
/* Handles writing logic that are agnostic of datatype, but not directly operations to db. */
/* Usage: after constructor, initialize with writeHandler.start. Assign value to idValue whever you have it. */
export class WriteHandler extends DatabaseHandler {
table: PrimaryTables
writeList: WriteItem[] = []
idColumn: string
idValue?: string | number
constructor(dbName: string, table: PrimaryTables) {
constructor(dbName: string, table: PrimaryTables, idColumn: string) {
super(dbName)
this.table = table
this.idColumn = idColumn
}
async createRow<T extends Record<string, DbValue>>(
@@ -44,7 +49,7 @@ export class WriteHandler extends DatabaseHandler {
}
async createObject<T extends Record<string, unknown>>(table: AllowedTables, object: T, idColumns: string[]) {
const itemsToWrite = getItemList(object)
const itemsToWrite = getItemList({ ...object }, true)
return await this.createRow<Record<keyof T, DbValue>>(table, itemsToWrite, idColumns)
}
@@ -53,4 +58,26 @@ export class WriteHandler extends DatabaseHandler {
const itemsToWrite = getItemList(object)
return await this.updateRow<Record<keyof T, DbValue>>(table, itemsToWrite, ids)
}
async upsertObject<T extends Record<string, unknown>>(table: AllowedTables, object: T, idColumns: string[]) {
if (idColumns.includes(this.idColumn) && this.idValue && !object[this.idColumn]) {
;(object as Record<string, unknown>)[this.idColumn] = this.idValue
return await this.createObject(table, object, idColumns)
}
return await this.updateObject<T>(table, object, idColumns)
}
async upsertList<T extends { rowState?: RowState }>(table: AllowedTables, objects: T[], ids: string[]) {
for (const object of objects) {
const rowState = object.rowState
if (rowState === 'new') {
await this.upsertObject(table, object, ids)
} else if (rowState === 'removed') {
await this.delete(
table,
ids.map(id => ({ column: id, value: object[id as keyof T] as DbValue }))
)
}
}
}
}