mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
WIP, edit writeHandler and write locality species stuff
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { EditDataType, LocalityDetailsType, LocalitySpecies } from '../../../../frontend/src/backendTypes'
|
||||
import {
|
||||
EditDataType,
|
||||
LocalityDetailsType,
|
||||
LocalitySpeciesDetailsType,
|
||||
SpeciesDetailsType,
|
||||
} from '../../../../frontend/src/backendTypes'
|
||||
import { NOW_DB_NAME } from '../../utils/config'
|
||||
import { getItemList } from '../writeOperations/utils'
|
||||
import { WriteHandler } from '../writeOperations/writeHandler'
|
||||
import { DbValue } from './writeUtils'
|
||||
|
||||
export const writeLocality = async (locality: EditDataType<LocalityDetailsType>) => {
|
||||
const isNew: boolean = !!locality.lid
|
||||
const writeHandler = new WriteHandler(NOW_DB_NAME, 'now_loc')
|
||||
await writeHandler.start()
|
||||
for (const ls of locality.now_ls) {
|
||||
@@ -17,12 +21,21 @@ export const writeLocality = async (locality: EditDataType<LocalityDetailsType>)
|
||||
}
|
||||
|
||||
/* Writes now_ls entries, and also any new species inside. */
|
||||
const writeLocalitySpecies = async (writeHandler: WriteHandler, localitySpecies: EditDataType<LocalitySpecies>) => {
|
||||
const writeLocalitySpecies = async (
|
||||
writeHandler: WriteHandler,
|
||||
localitySpecies: EditDataType<LocalitySpeciesDetailsType>
|
||||
) => {
|
||||
let species_id: DbValue | undefined = localitySpecies.com_species!.species_id
|
||||
if (!localitySpecies.species_id) {
|
||||
// const { species_id } = await writeHandler.writeTable('com_species', )
|
||||
species_id = await writeSpecies(writeHandler, localitySpecies.com_species!)
|
||||
}
|
||||
const items = getItemList(localitySpecies)
|
||||
return await writeHandler.writeTable('now_ls', items, [], ['lid', 'species_id'])
|
||||
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
|
||||
}
|
||||
|
||||
const deleteLocalitySpecies = async (writeHandler: WriteHandler, lid: number, species_id: number) => {
|
||||
|
||||
@@ -14,13 +14,13 @@ import {
|
||||
getFieldTypes,
|
||||
getOldData,
|
||||
ids,
|
||||
isEmptyValue,
|
||||
logAllUpdates,
|
||||
printJSON,
|
||||
tablesToNotLog,
|
||||
} from './writeUtils'
|
||||
import { NOW_DB_NAME } from '../../utils/config'
|
||||
import { PoolConnection } from 'mariadb'
|
||||
import { valueIsDifferent } from '../writeOperations/utils'
|
||||
|
||||
const query = async (queryString: string, values: Array<DbValue>, conn: PoolConnection) => {
|
||||
const result: object = await conn.query(queryString, values)
|
||||
@@ -35,7 +35,7 @@ export type WriteContext = {
|
||||
type: ActionType
|
||||
}
|
||||
|
||||
const writeTable = async <T extends CustomObject>(obj: T, tableName: AllowedTables, writeContext: WriteContext) => {
|
||||
const writeTable = async <T extends CustomObject>(obj: T, tableName: AllowedTables, writeHandler: WriteHandler) => {
|
||||
const oldObj = await getOldData(obj, tableName)
|
||||
|
||||
const allFields = Object.keys(obj).filter(f => allowedFields[f])
|
||||
@@ -57,10 +57,10 @@ const writeTable = async <T extends CustomObject>(obj: T, tableName: AllowedTabl
|
||||
We will first recourse into that, as we cannot write the parent table itself if we don't have the id of the possibly newly-created relation.
|
||||
So we write all objectFields and take their id's to be written later */
|
||||
for (const objectField of objectFields) {
|
||||
const newId = await writeTable(obj[objectField] as CustomObject, objectField, writeContext)
|
||||
const lastItem = ids[objectField].length - 1
|
||||
const newId = await writeTable(obj[objectField] as CustomObject, objectField, writeHandler)
|
||||
const lastIdIndex = ids[objectField].length - 1
|
||||
// get the relevant id name from ids: the order is so that last item is the relevant id. e.g. now_ls
|
||||
const idFieldName = ids[objectField][lastItem]
|
||||
const idFieldName = ids[objectField][lastIdIndex]
|
||||
relationIds[idFieldName] = newId
|
||||
}
|
||||
|
||||
@@ -75,10 +75,7 @@ const writeTable = async <T extends CustomObject>(obj: T, tableName: AllowedTabl
|
||||
const newValue = relationIds[field] ?? (obj[field as keyof object] as CustomObject)
|
||||
const oldValue = oldObj?.[field as keyof object]
|
||||
|
||||
// Skipping the values that aren't changed: including differences in empty values (etc. null and "") or bigint/number different type
|
||||
if (newValue === oldValue) continue
|
||||
if (isEmptyValue(newValue) && isEmptyValue(oldValue)) continue
|
||||
if (typeof oldValue === 'bigint' && typeof newValue === 'number' && BigInt(newValue) === oldValue) continue
|
||||
if (!valueIsDifferent(newValue, oldValue)) continue
|
||||
|
||||
// Add the fields to be written, we will actually write them at the end.
|
||||
if (!isRelationField || newValue !== undefined)
|
||||
|
||||
@@ -97,7 +97,7 @@ export const logAllUpdates = async (
|
||||
// if we are editing now_loc and this entry is triggered by now_ls (entry for com_species),
|
||||
// the id will be "species_id", not "lid".
|
||||
const idColumn = getIdColumn(targetTable)
|
||||
const secondaryId = writeListItem.items.find(item => item.column === idColumn)?.value
|
||||
const secondaryId = writeListItem.items.find(item => item.column === idColumn)?.value as string | number
|
||||
if (!secondaryId)
|
||||
throw new Error(`Error when creating update entries: id not found for targetTable: ${targetTable}`)
|
||||
if (!secondaryUpdateEntries[targetTable]) secondaryUpdateEntries[targetTable] = {}
|
||||
@@ -352,7 +352,7 @@ export type WriteItem = {
|
||||
}
|
||||
|
||||
// Possible types of values that are read from db or written in there. BigInt is handled as number.
|
||||
export type DbValue = string | number | null
|
||||
export type DbValue = string | number | null | boolean
|
||||
|
||||
export const allowedFields: Record<string, boolean | undefined> = {}
|
||||
const addFieldsToAllowed = (fields: string[]) =>
|
||||
|
||||
@@ -28,11 +28,11 @@ export class DatabaseHandler {
|
||||
return { values: items.map(item => item.value), columns: items.map(item => item.column) }
|
||||
}
|
||||
|
||||
async insert(table: AllowedTables, items: DbWriteItem[], returnColumns?: string[]) {
|
||||
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(`INSERT INTO ${this.dbName}.${table} (?) VALUES (?) ${returnString}`, [
|
||||
return await this.executeQuery<T>(`INSERT INTO ${this.dbName}.${table} (?) VALUES (?) ${returnString}`, [
|
||||
columns,
|
||||
values,
|
||||
])
|
||||
@@ -43,7 +43,7 @@ export class DatabaseHandler {
|
||||
const columnsString = columns.join(', ')
|
||||
|
||||
const { columns: idColumns, values: idValues } = this.getValuesAndColumns(ids)
|
||||
const whereClause = `${idColumns.map(idColumn => `${idColumn} = ?`).join(' AND ')}`
|
||||
const whereClause = createWhereClause(idColumns)
|
||||
|
||||
await this.executeQuery(`UPDATE ${this.dbName}.${table} (${columnsString}) WHERE ${whereClause}`, [
|
||||
values,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AllowedTables, PrimaryTables, WriteItem } from '../write/writeUtils'
|
||||
import { AllowedTables, DbValue, PrimaryTables, WriteItem } from '../write/writeUtils'
|
||||
import { DatabaseHandler, DbWriteItem } from './databaseHandler'
|
||||
import { valueIsDifferent } from './utils'
|
||||
import { getItemList, valueIsDifferent } from './utils'
|
||||
|
||||
/* Handles writing logic that are agnostic of datatype, but not directly operations to db. */
|
||||
export class WriteHandler extends DatabaseHandler {
|
||||
@@ -12,17 +12,21 @@ export class WriteHandler extends DatabaseHandler {
|
||||
this.table = table
|
||||
}
|
||||
|
||||
async createRow<T extends Record<string, DbValue>>(
|
||||
table: AllowedTables,
|
||||
items: DbWriteItem[],
|
||||
idsToReturn: string[]
|
||||
) {
|
||||
this.writeList.push({ table, type: 'add', items: items.map(item => ({ ...item, table })) })
|
||||
return await super.insert<T>(table, items, idsToReturn)
|
||||
}
|
||||
|
||||
/* Checks each field for their old value and if they did not (meaningfully) change,
|
||||
they are skipped, otherwise they are written to database.
|
||||
table: Table to write to
|
||||
items: Column & value pairs that should be written
|
||||
ids: Column & value pairs that define which item to write to. Empty if new item. */
|
||||
async writeTable<T>(table: AllowedTables, items: DbWriteItem[], ids: DbWriteItem[], idsToReturn: string[]) {
|
||||
if (ids.length === 0) {
|
||||
this.writeList.push({ table, type: 'add', items: items.map(item => ({ ...item, table })) })
|
||||
return await super.insert(table, items, idsToReturn)
|
||||
}
|
||||
|
||||
async updateRow<T extends Record<string, DbValue>>(table: AllowedTables, items: DbWriteItem[], ids: DbWriteItem[]) {
|
||||
const oldObject = await super.select<T>(table, [], ids)
|
||||
const fieldsToWrite: DbWriteItem[] = []
|
||||
|
||||
@@ -38,4 +42,15 @@ export class WriteHandler extends DatabaseHandler {
|
||||
|
||||
return await super.update(table, fieldsToWrite, ids)
|
||||
}
|
||||
|
||||
async createObject<T extends Record<string, unknown>>(table: AllowedTables, object: T, idColumns: string[]) {
|
||||
const itemsToWrite = getItemList(object)
|
||||
return await this.createRow<Record<keyof T, DbValue>>(table, itemsToWrite, idColumns)
|
||||
}
|
||||
|
||||
async updateObject<T extends Record<string, unknown>>(table: AllowedTables, object: T, idColumns: string[]) {
|
||||
const ids = idColumns.map(column => ({ column, value: object[column] as DbValue }))
|
||||
const itemsToWrite = getItemList(object)
|
||||
return await this.updateRow<Record<keyof T, DbValue>>(table, itemsToWrite, ids)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -39,6 +39,7 @@ export type SedimentaryStructureValues = Prisma.now_ss_values
|
||||
export type CollectingMethod = Prisma.now_coll_meth
|
||||
export type LocalityProject = Prisma.now_plr & { now_proj: Prisma.now_proj }
|
||||
export type LocalitySpecies = FixBigInt<Prisma.now_ls> & { com_species: SpeciesType }
|
||||
export type LocalitySpeciesDetailsType = FixBigInt<Prisma.now_ls> & { com_species: SpeciesDetailsType }
|
||||
export type SpeciesLocality = FixBigInt<Prisma.now_ls> & { now_loc: Prisma.now_loc }
|
||||
export type LocalityUpdate = Prisma.now_lau & { now_lr: LocalityReference[] } & { updates: UpdateLog[] }
|
||||
export type SpeciesUpdate = Prisma.now_sau & { now_sr: Prisma.now_sr }
|
||||
@@ -59,7 +60,7 @@ export type LocalityDetailsType = Prisma.now_loc & {
|
||||
} & {
|
||||
projects: Array<Project>
|
||||
} & {
|
||||
now_ls: Array<LocalitySpecies>
|
||||
now_ls: Array<LocalitySpeciesDetailsType>
|
||||
} & { now_plr: Array<LocalityProject> } & { now_syn_loc: Array<LocalitySynonym> } & {
|
||||
now_ss: SedimentaryStructure[]
|
||||
} & {
|
||||
|
||||
Reference in New Issue
Block a user