diff --git a/helpers/functions.sqlFilters.d.ts b/helpers/functions.sqlFilters.d.ts new file mode 100644 index 00000000..e65e0c3a --- /dev/null +++ b/helpers/functions.sqlFilters.d.ts @@ -0,0 +1,15 @@ +declare type LotNameSearchType = "startsWith" | "endsWith" | ""; +export declare const getLotNameWhereClause: (lotName: string, lotNameSearchType: LotNameSearchType, lotsTableAlias?: string) => { + sqlWhereClause: string; + sqlParameters: any[]; +}; +declare type OccupancyTime = "" | "current" | "past" | "future"; +export declare const getOccupancyTimeWhereClause: (occupancyTime: OccupancyTime, lotOccupanciesTableAlias?: string) => { + sqlWhereClause: string; + sqlParameters: any[]; +}; +export declare const getOccupantNameWhereClause: (occupantName: string, tableAlias?: string) => { + sqlWhereClause: string; + sqlParameters: any[]; +}; +export {}; diff --git a/helpers/functions.sqlFilters.js b/helpers/functions.sqlFilters.js new file mode 100644 index 00000000..68cccf46 --- /dev/null +++ b/helpers/functions.sqlFilters.js @@ -0,0 +1,83 @@ +import { dateToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js"; +export const getLotNameWhereClause = (lotName, lotNameSearchType, lotsTableAlias = "l") => { + let sqlWhereClause = ""; + const sqlParameters = []; + if (lotName) { + switch (lotNameSearchType) { + case "startsWith": { + sqlWhereClause += " and " + lotsTableAlias + ".lotName like ? || '%'"; + sqlParameters.push(lotName); + break; + } + case "endsWith": { + sqlWhereClause += " and " + lotsTableAlias + ".lotName like '%' || ?"; + sqlParameters.push(lotName); + break; + } + default: { + const lotNamePieces = lotName.toLowerCase().split(" "); + for (const lotNamePiece of lotNamePieces) { + sqlWhereClause += " and instr(lower(" + lotsTableAlias + ".lotName), ?)"; + sqlParameters.push(lotNamePiece); + } + } + } + } + return { + sqlWhereClause, + sqlParameters + }; +}; +export const getOccupancyTimeWhereClause = (occupancyTime, lotOccupanciesTableAlias = "o") => { + let sqlWhereClause = ""; + const sqlParameters = []; + if (occupancyTime) { + const currentDateString = dateToInteger(new Date()); + switch (occupancyTime) { + case "current": { + sqlWhereClause += + " and " + + lotOccupanciesTableAlias + + ".occupancyStartDate <= ? and (" + + lotOccupanciesTableAlias + + ".occupancyEndDate is null or " + + lotOccupanciesTableAlias + + ".occupancyEndDate >= ?)"; + sqlParameters.push(currentDateString, currentDateString); + break; + } + case "past": { + sqlWhereClause += " and " + lotOccupanciesTableAlias + ".occupancyEndDate < ?"; + sqlParameters.push(currentDateString); + break; + } + case "future": { + sqlWhereClause += " and " + lotOccupanciesTableAlias + ".occupancyStartDate > ?"; + sqlParameters.push(currentDateString); + break; + } + } + } + return { + sqlWhereClause, + sqlParameters + }; +}; +export const getOccupantNameWhereClause = (occupantName, tableAlias = "o") => { + let sqlWhereClause = ""; + const sqlParameters = []; + if (occupantName) { + const occupantNamePieces = occupantName.toLowerCase().split(" "); + for (const occupantNamePiece of occupantNamePieces) { + sqlWhereClause += + " and " + + tableAlias + + ".lotOccupancyId in (select lotOccupancyId from LotOccupancyOccupants where recordDelete_timeMillis is null and instr(lower(occupantName), ?))"; + sqlParameters.push(occupantNamePiece); + } + } + return { + sqlWhereClause, + sqlParameters + }; +}; diff --git a/helpers/functions.sqlFilters.ts b/helpers/functions.sqlFilters.ts new file mode 100644 index 00000000..902e90ae --- /dev/null +++ b/helpers/functions.sqlFilters.ts @@ -0,0 +1,106 @@ +import { dateToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js"; + +type LotNameSearchType = "startsWith" | "endsWith" | ""; + +export const getLotNameWhereClause = ( + lotName: string, + lotNameSearchType: LotNameSearchType, + lotsTableAlias = "l" +) => { + let sqlWhereClause = ""; + const sqlParameters = []; + + if (lotName) { + switch (lotNameSearchType) { + case "startsWith": { + sqlWhereClause += " and " + lotsTableAlias + ".lotName like ? || '%'"; + sqlParameters.push(lotName); + break; + } + case "endsWith": { + sqlWhereClause += " and " + lotsTableAlias + ".lotName like '%' || ?"; + sqlParameters.push(lotName); + break; + } + default: { + const lotNamePieces = lotName.toLowerCase().split(" "); + for (const lotNamePiece of lotNamePieces) { + sqlWhereClause += " and instr(lower(" + lotsTableAlias + ".lotName), ?)"; + sqlParameters.push(lotNamePiece); + } + } + } + } + + return { + sqlWhereClause, + sqlParameters + }; +}; + +type OccupancyTime = "" | "current" | "past" | "future"; + +export const getOccupancyTimeWhereClause = ( + occupancyTime: OccupancyTime, + lotOccupanciesTableAlias = "o" +) => { + let sqlWhereClause = ""; + const sqlParameters = []; + + if (occupancyTime) { + const currentDateString = dateToInteger(new Date()); + + switch (occupancyTime) { + case "current": { + sqlWhereClause += + " and " + + lotOccupanciesTableAlias + + ".occupancyStartDate <= ? and (" + + lotOccupanciesTableAlias + + ".occupancyEndDate is null or " + + lotOccupanciesTableAlias + + ".occupancyEndDate >= ?)"; + sqlParameters.push(currentDateString, currentDateString); + break; + } + + case "past": { + sqlWhereClause += " and " + lotOccupanciesTableAlias + ".occupancyEndDate < ?"; + sqlParameters.push(currentDateString); + break; + } + + case "future": { + sqlWhereClause += " and " + lotOccupanciesTableAlias + ".occupancyStartDate > ?"; + sqlParameters.push(currentDateString); + break; + } + } + } + + return { + sqlWhereClause, + sqlParameters + }; +}; + +export const getOccupantNameWhereClause = (occupantName: string, tableAlias = "o") => { + let sqlWhereClause = ""; + const sqlParameters = []; + + if (occupantName) { + const occupantNamePieces = occupantName.toLowerCase().split(" "); + for (const occupantNamePiece of occupantNamePieces) { + sqlWhereClause += + " and " + + tableAlias + + ".lotOccupancyId in (select lotOccupancyId from LotOccupancyOccupants where recordDelete_timeMillis is null and instr(lower(occupantName), ?))"; + sqlParameters.push(occupantNamePiece); + } + } + + return { + sqlWhereClause, + sqlParameters + }; +}; diff --git a/helpers/lotOccupancyDB/getLotOccupancies.js b/helpers/lotOccupancyDB/getLotOccupancies.js index bfcb3622..6dd1a9a8 100644 --- a/helpers/lotOccupancyDB/getLotOccupancies.js +++ b/helpers/lotOccupancyDB/getLotOccupancies.js @@ -1,9 +1,10 @@ import sqlite from "better-sqlite3"; import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; -import { dateIntegerToString, dateStringToInteger, dateToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.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 { getLotNameWhereClause, getOccupancyTimeWhereClause, getOccupantNameWhereClause } from "../functions.sqlFilters.js"; const buildWhereClause = (filters) => { let sqlWhereClause = " where o.recordDelete_timeMillis is null"; const sqlParameters = []; @@ -11,56 +12,19 @@ const buildWhereClause = (filters) => { sqlWhereClause += " and o.lotId = ?"; sqlParameters.push(filters.lotId); } - if (filters.lotName) { - if (filters.lotNameSearchType === "startsWith") { - sqlWhereClause += " and l.lotName like ? || '%'"; - sqlParameters.push(filters.lotName); - } - else if (filters.lotNameSearchType === "endsWith") { - sqlWhereClause += " and l.lotName like '%' || ?"; - sqlParameters.push(filters.lotName); - } - else { - const lotNamePieces = filters.lotName.toLowerCase().split(" "); - for (const lotNamePiece of lotNamePieces) { - sqlWhereClause += " and instr(lower(l.lotName), ?)"; - sqlParameters.push(lotNamePiece); - } - } - } - if (filters.occupantName) { - const occupantNamePieces = filters.occupantName.toLowerCase().split(" "); - for (const occupantNamePiece of occupantNamePieces) { - sqlWhereClause += - " and o.lotOccupancyId in (select oo.lotOccupancyId from LotOccupancyOccupants oo where oo.recordDelete_timeMillis is null and instr(lower(oo.occupantName), ?))"; - sqlParameters.push(occupantNamePiece); - } - } + const lotNameFilters = getLotNameWhereClause(filters.lotName, filters.lotNameSearchType, "l"); + sqlWhereClause += lotNameFilters.sqlWhereClause; + sqlParameters.push(...lotNameFilters.sqlParameters); + const occupantNameFilters = getOccupantNameWhereClause(filters.occupantName, "o"); + sqlWhereClause += occupantNameFilters.sqlWhereClause; + sqlParameters.push(...occupantNameFilters.sqlParameters); if (filters.occupancyTypeId) { sqlWhereClause += " and o.occupancyTypeId = ?"; sqlParameters.push(filters.occupancyTypeId); } - if (filters.occupancyTime) { - const currentDateString = dateToInteger(new Date()); - switch (filters.occupancyTime) { - case "current": { - sqlWhereClause += - " and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)"; - sqlParameters.push(currentDateString, currentDateString); - break; - } - case "past": { - sqlWhereClause += " and o.occupancyEndDate < ?"; - sqlParameters.push(currentDateString); - break; - } - case "future": { - sqlWhereClause += " and o.occupancyStartDate > ?"; - sqlParameters.push(currentDateString); - break; - } - } - } + 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)); diff --git a/helpers/lotOccupancyDB/getLotOccupancies.ts b/helpers/lotOccupancyDB/getLotOccupancies.ts index e861fc1b..a67fe3ae 100644 --- a/helpers/lotOccupancyDB/getLotOccupancies.ts +++ b/helpers/lotOccupancyDB/getLotOccupancies.ts @@ -14,6 +14,7 @@ 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; @@ -47,60 +48,22 @@ const buildWhereClause = ( sqlParameters.push(filters.lotId); } - if (filters.lotName) { - if (filters.lotNameSearchType === "startsWith") { - sqlWhereClause += " and l.lotName like ? || '%'"; - sqlParameters.push(filters.lotName); - } else if (filters.lotNameSearchType === "endsWith") { - sqlWhereClause += " and l.lotName like '%' || ?"; - sqlParameters.push(filters.lotName); - } else { - const lotNamePieces = filters.lotName.toLowerCase().split(" "); - for (const lotNamePiece of lotNamePieces) { - sqlWhereClause += " and instr(lower(l.lotName), ?)"; - sqlParameters.push(lotNamePiece); - } - } - } + const lotNameFilters = getLotNameWhereClause(filters.lotName, filters.lotNameSearchType, "l"); + sqlWhereClause += lotNameFilters.sqlWhereClause; + sqlParameters.push(...lotNameFilters.sqlParameters); - if (filters.occupantName) { - const occupantNamePieces = filters.occupantName.toLowerCase().split(" "); - for (const occupantNamePiece of occupantNamePieces) { - sqlWhereClause += - " and o.lotOccupancyId in (select oo.lotOccupancyId from LotOccupancyOccupants oo where oo.recordDelete_timeMillis is null and instr(lower(oo.occupantName), ?))"; - sqlParameters.push(occupantNamePiece); - } - } + const occupantNameFilters = getOccupantNameWhereClause(filters.occupantName, "o"); + sqlWhereClause += occupantNameFilters.sqlWhereClause; + sqlParameters.push(...occupantNameFilters.sqlParameters); if (filters.occupancyTypeId) { sqlWhereClause += " and o.occupancyTypeId = ?"; sqlParameters.push(filters.occupancyTypeId); } - if (filters.occupancyTime) { - const currentDateString = dateToInteger(new Date()); - - switch (filters.occupancyTime) { - case "current": { - sqlWhereClause += - " and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)"; - sqlParameters.push(currentDateString, currentDateString); - break; - } - - case "past": { - sqlWhereClause += " and o.occupancyEndDate < ?"; - sqlParameters.push(currentDateString); - break; - } - - case "future": { - sqlWhereClause += " and o.occupancyStartDate > ?"; - sqlParameters.push(currentDateString); - break; - } - } - } + const occupancyTimeFilters = getOccupancyTimeWhereClause(filters.occupancyTime, "o"); + sqlWhereClause += occupancyTimeFilters.sqlWhereClause; + sqlParameters.push(...occupancyTimeFilters.sqlParameters); if (filters.occupancyStartDateString) { sqlWhereClause += " and o.occupancyStartDate = ?"; diff --git a/helpers/lotOccupancyDB/getLots.js b/helpers/lotOccupancyDB/getLots.js index a8b7a1a0..d94229f3 100644 --- a/helpers/lotOccupancyDB/getLots.js +++ b/helpers/lotOccupancyDB/getLots.js @@ -2,26 +2,13 @@ import sqlite from "better-sqlite3"; import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; import { dateToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js"; import * as configFunctions from "../functions.config.js"; +import { getLotNameWhereClause } from "../functions.sqlFilters.js"; const buildWhereClause = (filters) => { let sqlWhereClause = " where l.recordDelete_timeMillis is null"; const sqlParameters = []; - if (filters.lotName) { - if (filters.lotNameSearchType === "startsWith") { - sqlWhereClause += " and l.lotName like ? || '%'"; - sqlParameters.push(filters.lotName); - } - else if (filters.lotNameSearchType === "endsWith") { - sqlWhereClause += " and l.lotName like '%' || ?"; - sqlParameters.push(filters.lotName); - } - else { - const lotNamePieces = filters.lotName.toLowerCase().split(" "); - for (const lotNamePiece of lotNamePieces) { - sqlWhereClause += " and instr(lower(l.lotName), ?)"; - sqlParameters.push(lotNamePiece); - } - } - } + const lotNameFilters = getLotNameWhereClause(filters.lotName, filters.lotNameSearchType, "l"); + sqlWhereClause += lotNameFilters.sqlWhereClause; + sqlParameters.push(...lotNameFilters.sqlParameters); if (filters.mapId) { sqlWhereClause += " and l.mapId = ?"; sqlParameters.push(filters.mapId); diff --git a/helpers/lotOccupancyDB/getLots.ts b/helpers/lotOccupancyDB/getLots.ts index 078e143e..810d7a46 100644 --- a/helpers/lotOccupancyDB/getLots.ts +++ b/helpers/lotOccupancyDB/getLots.ts @@ -7,6 +7,7 @@ import { dateToInteger } from "@cityssm/expressjs-server-js/dateTimeFns.js"; import * as configFunctions from "../functions.config.js"; import type * as recordTypes from "../../types/recordTypes"; +import { getLotNameWhereClause } from "../functions.sqlFilters.js"; interface GetLotsFilters { lotNameSearchType?: "" | "startsWith" | "endsWith"; @@ -26,24 +27,11 @@ interface GetLotsOptions { const buildWhereClause = (filters: GetLotsFilters): { sqlWhereClause: string; sqlParameters: unknown[];} => { let sqlWhereClause = " where l.recordDelete_timeMillis is null"; const sqlParameters: unknown[] = []; + + const lotNameFilters = getLotNameWhereClause(filters.lotName, filters.lotNameSearchType, "l"); + sqlWhereClause += lotNameFilters.sqlWhereClause; + sqlParameters.push(...lotNameFilters.sqlParameters); - if (filters.lotName) { - if (filters.lotNameSearchType === "startsWith") { - sqlWhereClause += " and l.lotName like ? || '%'"; - sqlParameters.push(filters.lotName); - } else if (filters.lotNameSearchType === "endsWith") { - sqlWhereClause += " and l.lotName like '%' || ?"; - sqlParameters.push(filters.lotName); - } else { - const lotNamePieces = filters.lotName.toLowerCase().split(" "); - for (const lotNamePiece of lotNamePieces) { - sqlWhereClause += " and instr(lower(l.lotName), ?)"; - sqlParameters.push(lotNamePiece); - } - } - } - - if (filters.mapId) { sqlWhereClause += " and l.mapId = ?"; sqlParameters.push(filters.mapId);