mirror of
https://github.com/nowcommunity/nowdatabase.git
synced 2026-10-12 19:13:52 +03:00
new way in progress
This commit is contained in:
@@ -2,16 +2,14 @@ import { logDb, nowDb, pool } from '../utils/db'
|
||||
import { EditDataType, LocalityDetailsType } from '../../../frontend/src/backendTypes'
|
||||
import Prisma from '../../prisma/generated/now_test_client'
|
||||
import { validateLocality } from '../../../frontend/src/validators/locality'
|
||||
import { diff } from 'deep-object-diff'
|
||||
import { filterFields } from './writeUtils'
|
||||
import { ValidationObject } from '../../../frontend/src/validators/validator'
|
||||
import { logger } from '../utils/logger'
|
||||
import { fixBigInt } from '../utils/common'
|
||||
import { testWrite } from './write'
|
||||
import { write } from './write/write'
|
||||
|
||||
export const getAllLocalities = async (onlyPublic: boolean) => {
|
||||
const where = onlyPublic ? { loc_status: false } : {}
|
||||
await testWrite()
|
||||
console.log('moi')
|
||||
const result = await nowDb.now_loc.findMany({
|
||||
select: {
|
||||
lid: true,
|
||||
@@ -30,7 +28,6 @@ export const getAllLocalities = async (onlyPublic: boolean) => {
|
||||
|
||||
export const getLocalityDetails = async (id: number) => {
|
||||
// TODO: Check if user has access
|
||||
|
||||
const result = await nowDb.now_loc.findUnique({
|
||||
where: { lid: id },
|
||||
include: {
|
||||
@@ -80,14 +77,7 @@ export const getLocalityDetails = async (id: number) => {
|
||||
updates: logResult.filter(logRow => logRow.luid === lau.luid),
|
||||
}))
|
||||
if (!result) return null
|
||||
const { now_ls, now_mus, now_plr, ...locality } = result
|
||||
const localityDetails = {
|
||||
...locality,
|
||||
museums: now_mus.map(museum => museum.com_mlist),
|
||||
projects: now_plr.map(project => project.now_proj),
|
||||
species: now_ls.map(species => species.com_species),
|
||||
}
|
||||
return JSON.parse(fixBigInt(localityDetails)!) as LocalityDetailsType
|
||||
return JSON.parse(fixBigInt(result)!) as LocalityDetailsType
|
||||
}
|
||||
|
||||
export const fixEditedLocality = (editedLocality: EditDataType<LocalityDetailsType>) => {
|
||||
@@ -110,15 +100,9 @@ export const validateEntireLocality = (editedFields: EditDataType<Prisma.now_loc
|
||||
export const processLocalityForEdit = async (editedLocality: EditDataType<LocalityDetailsType>) => {
|
||||
const fixedEditedLocality = fixEditedLocality(editedLocality)
|
||||
const oldLocality = await getLocalityDetails(fixedEditedLocality.lid!)
|
||||
const difference = diff(oldLocality!, fixedEditedLocality)
|
||||
|
||||
const { filteredFields, filteredObject } = filterFields(
|
||||
difference as EditDataType<LocalityDetailsType>,
|
||||
nowDb.now_loc.fields as unknown as Record<string, unknown>
|
||||
)
|
||||
const validationErrors = validateEntireLocality(filteredObject)
|
||||
if (validationErrors.length > 0) return { validationErrors }
|
||||
const result = await writeLocality(oldLocality!.lid, filteredFields)
|
||||
// const validationErrors = validateEntireLocality(editedLocality)
|
||||
// if (validationErrors.length > 0) return { validationErrors }
|
||||
const result = write(editedLocality, 'now_loc', oldLocality!)
|
||||
return { result }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import {
|
||||
EditDataType,
|
||||
LocalityDetailsType,
|
||||
SpeciesDetailsType,
|
||||
TimeBoundDetailsType,
|
||||
TimeUnitDetailsType,
|
||||
} from '../../../frontend/src/backendTypes'
|
||||
import { diff } from 'deep-object-diff'
|
||||
import { isNumeric, printJSON, revertFieldNames } from './writeUtils'
|
||||
type WriteFunction = (
|
||||
data: EditDataType<LocalityDetailsType | SpeciesDetailsType | TimeUnitDetailsType | TimeBoundDetailsType>,
|
||||
tableName: string,
|
||||
oldObject: EditDataType<LocalityDetailsType | SpeciesDetailsType | TimeUnitDetailsType | TimeBoundDetailsType>
|
||||
) => string
|
||||
|
||||
const ids = { now_loc: 'lid', now_ls: ['lid', 'species_id'] }
|
||||
|
||||
type Item = { column: string; value: any }
|
||||
type WriteItem = { table: string; type: 'add' | 'update' | 'delete'; items: Item[] }
|
||||
|
||||
export const write: WriteFunction = (data, tableName, oldObject) => {
|
||||
console.log('Write')
|
||||
const writeList: WriteItem[] = []
|
||||
|
||||
const writeTable = (data: object, tableName: string, oldObject: object, parentTable?: string) => {
|
||||
console.log(
|
||||
`writeTable called tableName: ${tableName}\n, oldObject: ${oldObject === undefined ? 'undefined' : 'is defined'}\n, parentTable: ${parentTable}`
|
||||
)
|
||||
const rowsToDelete: { table: string; rowId: string }[] = []
|
||||
const fieldsToWrite: any[] = []
|
||||
|
||||
for (const field of Object.keys(data)) {
|
||||
const value = data[field as keyof object] as string | number | undefined
|
||||
console.log(`Field ${field}`)
|
||||
if (Array.isArray(value)) {
|
||||
console.log('Writing array:')
|
||||
for (const [index, item] of value.entries()) {
|
||||
console.log(`* Index: ${index} Item: ${printJSON(item)}`)
|
||||
const oldArray = oldObject[field]
|
||||
const oldItem = oldArray?.[index]
|
||||
writeTable(item, field, oldItem, tableName)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isNumeric(field)) {
|
||||
console.log('is numeric')
|
||||
// We are iterating what was an array in original data
|
||||
if (value === undefined) {
|
||||
// Mark row to be deleted from join table
|
||||
const oldId = oldObject[field as keyof object]
|
||||
rowsToDelete.push({ table: tableName, rowId: oldId })
|
||||
continue
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
writeTable(value, tableName, oldObject)
|
||||
continue
|
||||
}
|
||||
} else if (typeof value === 'string' || typeof value === 'number') {
|
||||
fieldsToWrite.push({ field, value: data[field] })
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
writeTable(value, field, oldObject[field], tableName)
|
||||
}
|
||||
}
|
||||
if (fieldsToWrite.length === 0) return
|
||||
const oldId = oldObject?.[ids[tableName]]
|
||||
const result =
|
||||
oldId === undefined
|
||||
? writeList.push({ type: 'add', items: fieldsToWrite, table: tableName }) //query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (?) RETURNING ${ids[tableName]}`, values)
|
||||
: writeList.push({ type: 'update', items: fieldsToWrite, table: tableName }) //query(`UPDATE ${tableName} SET ${columns.map(c => `${c} = ?`).join(', ')} RETURNING ${ids[tableName]}`, [ ...values,])
|
||||
return { id: result[ids[tableName]] }
|
||||
}
|
||||
|
||||
console.log('Old object', JSON.stringify(oldObject, null, 2))
|
||||
console.log('New object', JSON.stringify(data, null, 2))
|
||||
const diffData = diff(oldObject, data)
|
||||
console.log('diff', printJSON(diffData))
|
||||
writeTable(diffData, tableName, oldObject)
|
||||
console.log(JSON.stringify(writeList, null, 2))
|
||||
return 'ok'
|
||||
}
|
||||
|
||||
const query = (queryString: string, values: unknown[]) => {
|
||||
console.log(`${queryString} | values: ${values}`)
|
||||
return 'ok'
|
||||
}
|
||||
|
||||
export const testUpdate = () => {
|
||||
const oldLoc = {
|
||||
lid: 1,
|
||||
age_comm: 'old comment',
|
||||
now_ls: [
|
||||
{
|
||||
lid: 2,
|
||||
species_id: 2,
|
||||
nis: 100,
|
||||
},
|
||||
],
|
||||
}
|
||||
const editedFields = {
|
||||
age_comm: 'write-testi',
|
||||
max_age: 5000,
|
||||
now_ls: [{ lid: 2, species_id: 2, source_name: 'locci' }],
|
||||
}
|
||||
write(revertFieldNames({ ...oldLoc, ...editedFields }), 'now_loc', oldLoc)
|
||||
}
|
||||
|
||||
export const testWrite = () => {
|
||||
console.log('testing update')
|
||||
testUpdate()
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import {
|
||||
EditDataType,
|
||||
LocalityDetailsType,
|
||||
SpeciesDetailsType,
|
||||
TimeBoundDetailsType,
|
||||
TimeUnitDetailsType,
|
||||
} from '../../../../frontend/src/backendTypes'
|
||||
import { revertFieldNames } from './writeUtils'
|
||||
|
||||
type WriteFunction = (
|
||||
data: EditDataType<LocalityDetailsType | SpeciesDetailsType | TimeUnitDetailsType | TimeBoundDetailsType>,
|
||||
tableName: string,
|
||||
oldObject: EditDataType<LocalityDetailsType | SpeciesDetailsType | TimeUnitDetailsType | TimeBoundDetailsType>
|
||||
) => string
|
||||
|
||||
const ids = { now_loc: 'lid', now_ls: 'species_id' }
|
||||
|
||||
type Item = { column: string; value: any }
|
||||
type WriteItem = { table: string; type: 'add' | 'update' | 'delete'; items: Item[] }
|
||||
|
||||
const getFindFunction = (tableName: string, newItem: any) => (item: any) => {
|
||||
if (tableName === 'now_ls') {
|
||||
// todo this should be com species when it is fixed
|
||||
if (item.species_id === newItem.species_id) return true
|
||||
}
|
||||
return false // TODO add all types
|
||||
}
|
||||
|
||||
// TODO change ignored fields to allowed fields. form those by taking prisma.model.fields, and adding the accepted relation fields.
|
||||
const ignoredFields = ['now_lau']
|
||||
export const write: WriteFunction = (data, tableName, oldObject) => {
|
||||
console.log('Write')
|
||||
const writeList: WriteItem[] = []
|
||||
const writeTable = (obj: object, tableName: string, oldObj: object | null) => {
|
||||
console.log(
|
||||
`writeTable called tableName: ${tableName}\n'} ${oldObj ? ' oldobj defined ' : ' no old object found '}`
|
||||
)
|
||||
const allFields = Object.keys(obj).filter(f => !ignoredFields.includes(f))
|
||||
const fields = allFields.filter(f => typeof obj[f as keyof object] !== 'object' || obj[f as keyof object] === null)
|
||||
const relationFields = allFields.filter(
|
||||
f => typeof obj[f as keyof object] === 'object' && obj[f as keyof object] !== null
|
||||
)
|
||||
console.log('fields: ', JSON.stringify(fields))
|
||||
console.log('relations: ', JSON.stringify(relationFields))
|
||||
const fieldsToWrite: Item[] = []
|
||||
const rowsToDelete: Item[] = []
|
||||
for (const field of fields) {
|
||||
const newValue = obj[field as keyof object] as any
|
||||
const oldValue = oldObj?.[field as keyof object]
|
||||
if (newValue === oldValue) continue
|
||||
console.log(
|
||||
`Field: ${field} Old value: ${oldValue} - ${typeof oldValue} New value: ${newValue} - ${typeof newValue}`
|
||||
)
|
||||
fieldsToWrite.push({ column: field, value: newValue })
|
||||
}
|
||||
|
||||
const columns = fieldsToWrite.map(({ column }) => column)
|
||||
const values = fieldsToWrite.map(({ value }) => value)
|
||||
const idFieldName = ids[tableName as keyof object] as string
|
||||
let id = obj[idFieldName as keyof object] as string
|
||||
if (values.length > 0) {
|
||||
if (id) {
|
||||
query(`UPDATE ${tableName} SET ${columns.map(c => `${c} = ?`).join(', ')} RETURNING ${idFieldName}`, [
|
||||
...values,
|
||||
])
|
||||
} else {
|
||||
id = query(`INSERT INTO ${tableName} (${columns.join(', ')}) VALUES (?) RETURNING ${idFieldName}`, values)
|
||||
}
|
||||
}
|
||||
for (const relationField of relationFields) {
|
||||
const value = obj[relationField]
|
||||
if (Array.isArray(value)) {
|
||||
const toBeDeleted: Item[] = value
|
||||
.filter(({ rowState }) => rowState === 'removed')
|
||||
.map(item => ({ column: relationField, value: item[idFieldName] }))
|
||||
rowsToDelete.push(...toBeDeleted)
|
||||
for (const item of value.filter(({ rowState }) => rowState !== 'removed')) {
|
||||
const itemWithId = { ...item } // TODO add id here when join tables added
|
||||
// console.log('item', item, JSON.stringify(item))
|
||||
writeTable(itemWithId, relationField, oldObj[relationField].find(getFindFunction(relationField, itemWithId)))
|
||||
}
|
||||
} else {
|
||||
// writing a relation object
|
||||
const itemWithId = { ...value, [idFieldName]: id }
|
||||
writeTable(itemWithId, relationField, oldObj?.[relationField as keyof object] as any)
|
||||
}
|
||||
}
|
||||
rowsToDelete.map(item => query(`DELETE FROM ? WHERE ? = ?`, [item.column, ids[item.column], item.value])) // NOTE column here is actually table name
|
||||
//console.log(JSON.stringify(fieldsToWrite, null, 2))
|
||||
}
|
||||
|
||||
console.log('Old object', JSON.stringify(oldObject, null, 2))
|
||||
console.log('New object', JSON.stringify(data, null, 2))
|
||||
writeTable(revertFieldNames(data), tableName, revertFieldNames(oldObject))
|
||||
// console.log(JSON.stringify(writeList, null, 2))
|
||||
return 'ok'
|
||||
}
|
||||
|
||||
const query = (queryString: string, values: any[]) => {
|
||||
console.log(`${queryString} | values: ${values.join(', ')}`)
|
||||
return 'some_id'
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
common utility functions for processing saving actions
|
||||
*/
|
||||
import { EditDataType } from '../../../frontend/src/backendTypes'
|
||||
import { EditDataType } from '../../../../frontend/src/backendTypes'
|
||||
|
||||
/*
|
||||
Returns object where only the "original" fields remain.
|
||||
Reference in New Issue
Block a user