mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
Add new methods to writeHandler, modify dbHandler, locality write works, now_ls works
This commit is contained in:
@@ -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' })
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -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 }))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user