/* eslint-disable @typescript-eslint/indent */ import sqlite from 'better-sqlite3' import { lotOccupancyDB as databasePath } from '../../data/databasePaths.js' import { dateIntegerToString, dateStringToInteger } from '@cityssm/expressjs-server-js/dateTimeFns.js' import * as configFunctions from '../functions.config.js' import { getOccupancyTypeById } from '../functions.cache.js' import { getLotOccupancyOccupants } from './getLotOccupancyOccupants.js' import type * as recordTypes from '../../types/recordTypes' import { getLotNameWhereClause, getOccupancyTimeWhereClause, getOccupantNameWhereClause } from '../functions.sqlFilters.js' interface GetLotOccupanciesFilters { lotId?: number | string occupancyTime?: '' | 'past' | 'current' | 'future' occupancyStartDateString?: string occupancyEffectiveDateString?: string occupantName?: string occupancyTypeId?: number | string mapId?: number | string lotNameSearchType?: '' | 'startsWith' | 'endsWith' lotName?: string lotTypeId?: number | string workOrderId?: number | string notWorkOrderId?: number | string } interface GetLotOccupanciesOptions { limit: -1 | number offset: number includeOccupants: boolean } function buildWhereClause(filters: GetLotOccupanciesFilters): { sqlWhereClause: string sqlParameters: unknown[] } { let sqlWhereClause = ' where o.recordDelete_timeMillis is null' const sqlParameters: unknown[] = [] if (filters.lotId) { sqlWhereClause += ' and o.lotId = ?' sqlParameters.push(filters.lotId) } const lotNameFilters = getLotNameWhereClause( filters.lotName, filters.lotNameSearchType ?? '', 'l' ) sqlWhereClause += lotNameFilters.sqlWhereClause sqlParameters.push(...lotNameFilters.sqlParameters) const occupantNameFilters = getOccupantNameWhereClause( filters.occupantName, 'o' ) if (occupantNameFilters.sqlParameters.length > 0) { sqlWhereClause += ' and o.lotOccupancyId in (select lotOccupancyId from LotOccupancyOccupants o where recordDelete_timeMillis is null' + occupantNameFilters.sqlWhereClause + ')' sqlParameters.push(...occupantNameFilters.sqlParameters) } if (filters.occupancyTypeId) { sqlWhereClause += ' and o.occupancyTypeId = ?' sqlParameters.push(filters.occupancyTypeId) } const occupancyTimeFilters = getOccupancyTimeWhereClause( filters.occupancyTime ?? '', 'o' ) sqlWhereClause += occupancyTimeFilters.sqlWhereClause sqlParameters.push(...occupancyTimeFilters.sqlParameters) if (filters.occupancyStartDateString) { sqlWhereClause += ' and o.occupancyStartDate = ?' sqlParameters.push(dateStringToInteger(filters.occupancyStartDateString)) } if (filters.occupancyEffectiveDateString) { sqlWhereClause += ' and (o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?))' sqlParameters.push( dateStringToInteger(filters.occupancyEffectiveDateString), dateStringToInteger(filters.occupancyEffectiveDateString) ) } if (filters.mapId) { sqlWhereClause += ' and l.mapId = ?' sqlParameters.push(filters.mapId) } if (filters.lotTypeId) { sqlWhereClause += ' and l.lotTypeId = ?' sqlParameters.push(filters.lotTypeId) } if (filters.workOrderId) { sqlWhereClause += ' and o.lotOccupancyId in (select lotOccupancyId from WorkOrderLotOccupancies where recordDelete_timeMillis is null and workOrderId = ?)' sqlParameters.push(filters.workOrderId) } if (filters.notWorkOrderId) { sqlWhereClause += ' and o.lotOccupancyId not in (select lotOccupancyId from WorkOrderLotOccupancies where recordDelete_timeMillis is null and workOrderId = ?)' sqlParameters.push(filters.notWorkOrderId) } return { sqlWhereClause, sqlParameters } } export function getLotOccupancies( filters: GetLotOccupanciesFilters, options: GetLotOccupanciesOptions, connectedDatabase?: sqlite.Database ): { count: number lotOccupancies: recordTypes.LotOccupancy[] } { const database = connectedDatabase ?? sqlite(databasePath, { readonly: true }) database.function('userFn_dateIntegerToString', dateIntegerToString) const { sqlWhereClause, sqlParameters } = buildWhereClause(filters) let count = options.limit const isLimited = options.limit !== -1 if (isLimited) { count = database .prepare( 'select count(*) as recordCount' + ' from LotOccupancies o' + ' left join Lots l on o.lotId = l.lotId' + sqlWhereClause ) .get(sqlParameters).recordCount } let lotOccupancies: recordTypes.LotOccupancy[] = [] if (count !== 0) { lotOccupancies = database .prepare( `select o.lotOccupancyId, o.occupancyTypeId, t.occupancyType, o.lotId, lt.lotType, l.lotName, l.mapId, m.mapName, o.occupancyStartDate, userFn_dateIntegerToString(o.occupancyStartDate) as occupancyStartDateString, o.occupancyEndDate, userFn_dateIntegerToString(o.occupancyEndDate) as occupancyEndDateString from LotOccupancies o left join OccupancyTypes t on o.occupancyTypeId = t.occupancyTypeId left join Lots l on o.lotId = l.lotId left join LotTypes lt on l.lotTypeId = lt.lotTypeId left join Maps m on l.mapId = m.mapId ${sqlWhereClause} order by o.occupancyStartDate desc, ifnull(o.occupancyEndDate, 99999999) desc, l.lotName, o.lotId, o.lotOccupancyId desc` + (isLimited ? ` limit ${options.limit} offset ${options.offset}` : '') ) .all(sqlParameters) if (!isLimited) { count = lotOccupancies.length } for (const lotOccupancy of lotOccupancies) { const occupancyType = getOccupancyTypeById(lotOccupancy.occupancyTypeId!) if (occupancyType) { lotOccupancy.printEJS = ( occupancyType.occupancyTypePrints ?? [] ).includes('*') ? configFunctions.getProperty('settings.lotOccupancy.prints')[0] : occupancyType.occupancyTypePrints![0] } if (options.includeOccupants) { lotOccupancy.lotOccupancyOccupants = getLotOccupancyOccupants( lotOccupancy.lotOccupancyId!, database ) } } } if (!connectedDatabase) { database.close() } return { count, lotOccupancies } } export default getLotOccupancies