lot name contains, starts with, or ends with

deepsource-autofix-76c6eb20
Dan Gowans 2022-10-05 13:38:57 -04:00
parent 69c97d0d02
commit 75ced51d7e
8 changed files with 224 additions and 173 deletions

View File

@ -8,6 +8,7 @@ interface GetLotOccupanciesFilters {
occupantName?: string; occupantName?: string;
occupancyTypeId?: number | string; occupancyTypeId?: number | string;
mapId?: number | string; mapId?: number | string;
lotNameSearchType?: "" | "startsWith" | "endsWith";
lotName?: string; lotName?: string;
lotTypeId?: number | string; lotTypeId?: number | string;
workOrderId?: number | string; workOrderId?: number | string;

View File

@ -15,10 +15,20 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
sqlParameters.push(filters.lotId); sqlParameters.push(filters.lotId);
} }
if (filters.lotName) { if (filters.lotName) {
const lotNamePieces = filters.lotName.toLowerCase().split(" "); if (filters.lotNameSearchType === "startsWith") {
for (const lotNamePiece of lotNamePieces) { sqlWhereClause += " and l.lotName like ? || '%'";
sqlWhereClause += " and instr(lower(l.lotName), ?)"; sqlParameters.push(filters.lotName);
sqlParameters.push(lotNamePiece); }
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) { if (filters.occupantName) {
@ -36,19 +46,22 @@ export const getLotOccupancies = (filters, options, connectedDatabase) => {
if (filters.occupancyTime) { if (filters.occupancyTime) {
const currentDateString = dateToInteger(new Date()); const currentDateString = dateToInteger(new Date());
switch (filters.occupancyTime) { switch (filters.occupancyTime) {
case "current": case "current": {
sqlWhereClause += sqlWhereClause +=
" and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)"; " and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)";
sqlParameters.push(currentDateString, currentDateString); sqlParameters.push(currentDateString, currentDateString);
break; break;
case "past": }
case "past": {
sqlWhereClause += " and o.occupancyEndDate < ?"; sqlWhereClause += " and o.occupancyEndDate < ?";
sqlParameters.push(currentDateString); sqlParameters.push(currentDateString);
break; break;
case "future": }
case "future": {
sqlWhereClause += " and o.occupancyStartDate > ?"; sqlWhereClause += " and o.occupancyStartDate > ?";
sqlParameters.push(currentDateString); sqlParameters.push(currentDateString);
break; break;
}
} }
} }
if (filters.occupancyStartDateString) { if (filters.occupancyStartDateString) {

View File

@ -20,6 +20,7 @@ interface GetLotOccupanciesFilters {
occupantName?: string; occupantName?: string;
occupancyTypeId?: number | string; occupancyTypeId?: number | string;
mapId?: number | string; mapId?: number | string;
lotNameSearchType?: "" | "startsWith" | "endsWith";
lotName?: string; lotName?: string;
lotTypeId?: number | string; lotTypeId?: number | string;
workOrderId?: number | string; workOrderId?: number | string;
@ -57,10 +58,18 @@ export const getLotOccupancies = (
} }
if (filters.lotName) { if (filters.lotName) {
const lotNamePieces = filters.lotName.toLowerCase().split(" "); if (filters.lotNameSearchType === "startsWith") {
for (const lotNamePiece of lotNamePieces) { sqlWhereClause += " and l.lotName like ? || '%'";
sqlWhereClause += " and instr(lower(l.lotName), ?)"; sqlParameters.push(filters.lotName);
sqlParameters.push(lotNamePiece); } 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);
}
} }
} }
@ -82,21 +91,24 @@ export const getLotOccupancies = (
const currentDateString = dateToInteger(new Date()); const currentDateString = dateToInteger(new Date());
switch (filters.occupancyTime) { switch (filters.occupancyTime) {
case "current": case "current": {
sqlWhereClause += sqlWhereClause +=
" and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)"; " and o.occupancyStartDate <= ? and (o.occupancyEndDate is null or o.occupancyEndDate >= ?)";
sqlParameters.push(currentDateString, currentDateString); sqlParameters.push(currentDateString, currentDateString);
break; break;
}
case "past": case "past": {
sqlWhereClause += " and o.occupancyEndDate < ?"; sqlWhereClause += " and o.occupancyEndDate < ?";
sqlParameters.push(currentDateString); sqlParameters.push(currentDateString);
break; break;
}
case "future": case "future": {
sqlWhereClause += " and o.occupancyStartDate > ?"; sqlWhereClause += " and o.occupancyStartDate > ?";
sqlParameters.push(currentDateString); sqlParameters.push(currentDateString);
break; break;
}
} }
} }

View File

@ -1,6 +1,7 @@
import sqlite from "better-sqlite3"; import sqlite from "better-sqlite3";
import type * as recordTypes from "../../types/recordTypes"; import type * as recordTypes from "../../types/recordTypes";
interface GetLotsFilters { interface GetLotsFilters {
lotNameSearchType?: "" | "startsWith" | "endsWith";
lotName?: string; lotName?: string;
mapId?: number | string; mapId?: number | string;
lotTypeId?: number | string; lotTypeId?: number | string;

View File

@ -10,10 +10,20 @@ export const getLots = (filters, options, connectedDatabase) => {
let sqlWhereClause = " where l.recordDelete_timeMillis is null"; let sqlWhereClause = " where l.recordDelete_timeMillis is null";
const sqlParameters = []; const sqlParameters = [];
if (filters.lotName) { if (filters.lotName) {
const lotNamePieces = filters.lotName.toLowerCase().split(" "); if (filters.lotNameSearchType === "startsWith") {
for (const lotNamePiece of lotNamePieces) { sqlWhereClause += " and l.lotName like ? || '%'";
sqlWhereClause += " and instr(lower(l.lotName), ?)"; sqlParameters.push(filters.lotName);
sqlParameters.push(lotNamePiece); }
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) { if (filters.mapId) {
@ -33,8 +43,7 @@ export const getLots = (filters, options, connectedDatabase) => {
sqlWhereClause += " and lotOccupancyCount > 0"; sqlWhereClause += " and lotOccupancyCount > 0";
} }
else if (filters.occupancyStatus === "unoccupied") { else if (filters.occupancyStatus === "unoccupied") {
sqlWhereClause += sqlWhereClause += " and (lotOccupancyCount is null or lotOccupancyCount = 0)";
" and (lotOccupancyCount is null or lotOccupancyCount = 0)";
} }
} }
if (filters.workOrderId) { if (filters.workOrderId) {
@ -88,12 +97,7 @@ export const getLots = (filters, options, connectedDatabase) => {
") o on l.lotId = o.lotId") + ") o on l.lotId = o.lotId") +
sqlWhereClause + sqlWhereClause +
" order by userFn_lotNameSortName(l.lotName), l.lotId" + " order by userFn_lotNameSortName(l.lotName), l.lotId" +
(options (options ? " limit " + options.limit + " offset " + options.offset : ""))
? " limit " +
options.limit +
" offset " +
options.offset
: ""))
.all(sqlParameters); .all(sqlParameters);
if (options.limit === -1) { if (options.limit === -1) {
count = lots.length; count = lots.length;

View File

@ -9,6 +9,7 @@ import * as configFunctions from "../functions.config.js";
import type * as recordTypes from "../../types/recordTypes"; import type * as recordTypes from "../../types/recordTypes";
interface GetLotsFilters { interface GetLotsFilters {
lotNameSearchType?: "" | "startsWith" | "endsWith";
lotName?: string; lotName?: string;
mapId?: number | string; mapId?: number | string;
lotTypeId?: number | string; lotTypeId?: number | string;
@ -40,13 +41,22 @@ export const getLots = (
const sqlParameters = []; const sqlParameters = [];
if (filters.lotName) { if (filters.lotName) {
const lotNamePieces = filters.lotName.toLowerCase().split(" "); if (filters.lotNameSearchType === "startsWith") {
for (const lotNamePiece of lotNamePieces) { sqlWhereClause += " and l.lotName like ? || '%'";
sqlWhereClause += " and instr(lower(l.lotName), ?)"; sqlParameters.push(filters.lotName);
sqlParameters.push(lotNamePiece); } 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) { if (filters.mapId) {
sqlWhereClause += " and l.mapId = ?"; sqlWhereClause += " and l.mapId = ?";
sqlParameters.push(filters.mapId); sqlParameters.push(filters.mapId);
@ -66,8 +76,7 @@ export const getLots = (
if (filters.occupancyStatus === "occupied") { if (filters.occupancyStatus === "occupied") {
sqlWhereClause += " and lotOccupancyCount > 0"; sqlWhereClause += " and lotOccupancyCount > 0";
} else if (filters.occupancyStatus === "unoccupied") { } else if (filters.occupancyStatus === "unoccupied") {
sqlWhereClause += sqlWhereClause += " and (lotOccupancyCount is null or lotOccupancyCount = 0)";
" and (lotOccupancyCount is null or lotOccupancyCount = 0)";
} }
} }
@ -82,25 +91,25 @@ export const getLots = (
let count: number; let count: number;
if (options.limit !== -1) { if (options.limit !== -1) {
count = database count = database
.prepare( .prepare(
"select count(*) as recordCount" + "select count(*) as recordCount" +
" from Lots l" + " from Lots l" +
(" left join (" + (" left join (" +
"select lotId, count(lotOccupancyId) as lotOccupancyCount" + "select lotId, count(lotOccupancyId) as lotOccupancyCount" +
" from LotOccupancies" + " from LotOccupancies" +
" where recordDelete_timeMillis is null" + " where recordDelete_timeMillis is null" +
" and occupancyStartDate <= " + " and occupancyStartDate <= " +
currentDate + currentDate +
" and (occupancyEndDate is null or occupancyEndDate >= " + " and (occupancyEndDate is null or occupancyEndDate >= " +
currentDate + currentDate +
")" + ")" +
" group by lotId" + " group by lotId" +
") o on l.lotId = o.lotId") + ") o on l.lotId = o.lotId") +
sqlWhereClause sqlWhereClause
) )
.get(sqlParameters).recordCount; .get(sqlParameters).recordCount;
} }
let lots: recordTypes.Lot[] = []; let lots: recordTypes.Lot[] = [];
@ -134,12 +143,7 @@ export const getLots = (
") o on l.lotId = o.lotId") + ") o on l.lotId = o.lotId") +
sqlWhereClause + sqlWhereClause +
" order by userFn_lotNameSortName(l.lotName), l.lotId" + " order by userFn_lotNameSortName(l.lotName), l.lotId" +
(options (options ? " limit " + options.limit + " offset " + options.offset : "")
? " limit " +
options.limit +
" offset " +
options.offset
: "")
) )
.all(sqlParameters); .all(sqlParameters);

View File

@ -33,38 +33,47 @@
<input id="searchFilter--limit" name="limit" type="hidden" value="100" /> <input id="searchFilter--limit" name="limit" type="hidden" value="100" />
<input id="searchFilter--offset" name="offset" type="hidden" value="0" /> <input id="searchFilter--offset" name="offset" type="hidden" value="0" />
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<div class="field"> <label class="label" for="searchFilter--lotName"><%= configFunctions.getProperty("aliases.lot") %></label>
<label class="label" for="searchFilter--lotName"><%= configFunctions.getProperty("aliases.lot") %></label> <div class="field has-addons">
<div class="control has-icons-left"> <div class="control has-icons-left">
<input class="input" id="searchFilter--lotName" name="lotName" accesskey="f" /> <div class="select">
<span class="icon is-small is-left"> <select id="selectFilter--lotNameSearchType" name="lotNameSearchType">
<i class="fas fa-search" aria-hidden="true"></i> <option value="">contains</option>
</span> <option value="startsWith">starts with</option>
</div> <option value="endsWith">ends with</option>
</div> </select>
</div> </div>
<div class="column"> <span class="icon is-small is-left">
<div class="field"> <i class="fas fa-search" aria-hidden="true"></i>
<label class="label" for="searchFilter--lotTypeId"><%= configFunctions.getProperty("aliases.lot") %> Type</label> </span>
<div class="control has-icons-left"> </div>
<div class="select is-fullwidth"> <div class="control is-expanded">
<select id="searchFilter--lotTypeId" name="lotTypeId"> <input class="input" id="searchFilter--lotName" name="lotName" />
<option value="">(All <%= configFunctions.getProperty("aliases.lot") %> Types)</option> </div>
<% for (const lotType of lotTypes) { %>
<option value="<%= lotType.lotTypeId %>" <%= (lotType.lotTypeId.toString() === lotTypeId) ? " selected" : "" %>>
<%= lotType.lotType || "(No Name)" %>
</option>
<% } %>
</select>
</div> </div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div> </div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--lotTypeId"><%= configFunctions.getProperty("aliases.lot") %> Type</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--lotTypeId" name="lotTypeId">
<option value="">(All <%= configFunctions.getProperty("aliases.lot") %> Types)</option>
<% for (const lotType of lotTypes) { %>
<option value="<%= lotType.lotTypeId %>" <%= (lotType.lotTypeId.toString() === lotTypeId) ? " selected" : "" %>>
<%= lotType.lotType || "(No Name)" %>
</option>
<% } %>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div>
</div> </div>
</div> </div>
</div>
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<div class="field"> <div class="field">

View File

@ -18,7 +18,7 @@
</nav> </nav>
<h1 class="title is-1"> <h1 class="title is-1">
Find an <%= configFunctions.getProperty("aliases.occupancy") %> Record Find an <%= configFunctions.getProperty("aliases.occupancy") %> Record
</h1> </h1>
<% if (user.userProperties.canUpdate) { %> <% if (user.userProperties.canUpdate) { %>
@ -34,110 +34,117 @@
<% } %> <% } %>
<div class="box"> <div class="box">
<form id="form--searchFilters"> <form id="form--searchFilters">
<input id="searchFilter--limit" name="limit" type="hidden" value="100" /> <input id="searchFilter--limit" name="limit" type="hidden" value="100" />
<input id="searchFilter--offset" name="offset" type="hidden" value="0" /> <input id="searchFilter--offset" name="offset" type="hidden" value="0" />
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<div class="field"> <div class="field">
<label class="label" for="searchFilter--occupantName"><%= configFunctions.getProperty("aliases.occupant") %> Name</label> <label class="label" for="searchFilter--occupantName"><%= configFunctions.getProperty("aliases.occupant") %> Name</label>
<div class="control has-icons-left"> <div class="control has-icons-left">
<input class="input" id="searchFilter--occupantName" name="occupantName" accesskey="f" /> <input class="input" id="searchFilter--occupantName" name="occupantName" accesskey="f" />
<span class="icon is-small is-left"> <span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i> <i class="fas fa-search" aria-hidden="true"></i>
</span> </span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--occupancyTypeId"><%= configFunctions.getProperty("aliases.occupancy") %> Type</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--occupancyTypeId" name="occupancyTypeId">
<option value="">(All <%= configFunctions.getProperty("aliases.occupancy") %> Types)</option>
<% for (const occupancyType of occupancyTypes) { %>
<option value="<%= occupancyType.occupancyTypeId %>"><%= occupancyType.occupancyType %></option>
<% } %>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--occupancyTime"><%= configFunctions.getProperty("aliases.occupancy") %> Time</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--occupancyTime" name="occupancyTime">
<option value="">(All Times)</option>
<option value="current" selected>Current</option>
<option value="past">Past</option>
<option value="future">Future</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="column"> <div class="columns">
<div class="field"> <div class="column">
<label class="label" for="searchFilter--occupancyTypeId"><%= configFunctions.getProperty("aliases.occupancy") %> Type</label> <div class="field">
<label class="label" for="searchFilter--mapId"><%= configFunctions.getProperty("aliases.map") %></label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--mapId" name="mapId">
<option value="">(All <%= configFunctions.getProperty("aliases.maps") %>)</option>
<% for (const map of maps) { %>
<option value="<%= map.mapId %>" <%= (map.mapId.toString() === mapId) ? " selected" : "" %>>
<%= map.mapName || "(No Name)" %>
</option>
<% } %>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--lotTypeId"><%= configFunctions.getProperty("aliases.lot") %> Type</label>
<div class="control has-icons-left"> <div class="control has-icons-left">
<div class="select is-fullwidth"> <div class="select is-fullwidth">
<select id="searchFilter--occupancyTypeId" name="occupancyTypeId"> <select id="searchFilter--lotTypeId" name="lotTypeId">
<option value="">(All <%= configFunctions.getProperty("aliases.occupancy") %> Types)</option> <option value="">(All <%= configFunctions.getProperty("aliases.lot") %> Types)</option>
<% for (const occupancyType of occupancyTypes) { %> <% for (const lotType of lotTypes) { %>
<option value="<%= occupancyType.occupancyTypeId %>"><%= occupancyType.occupancyType %></option> <option value="<%= lotType.lotTypeId %>"><%= lotType.lotType %></option>
<% } %> <% } %>
</select> </select>
</div> </div>
<span class="icon is-small is-left"> <span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i> <i class="fas fa-search" aria-hidden="true"></i>
</span> </span>
</div> </div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--occupancyTime"><%= configFunctions.getProperty("aliases.occupancy") %> Time</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--occupancyTime" name="occupancyTime">
<option value="">(All Times)</option>
<option value="current" selected>Current</option>
<option value="past">Past</option>
<option value="future">Future</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div> </div>
</div> </div>
</div> </div>
</div> <label class="label" for="searchFilter--lotName"><%= configFunctions.getProperty("aliases.lot") %></label>
<div class="columns"> <div class="field has-addons">
<div class="column">
<div class="field">
<label class="label" for="searchFilter--mapId"><%= configFunctions.getProperty("aliases.map") %></label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--mapId" name="mapId">
<option value="">(All <%= configFunctions.getProperty("aliases.maps") %>)</option>
<% for (const map of maps) { %>
<option value="<%= map.mapId %>" <%= (map.mapId.toString() === mapId) ? " selected" : "" %>>
<%= map.mapName || "(No Name)" %>
</option>
<% } %>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="searchFilter--lotName"><%= configFunctions.getProperty("aliases.lot") %></label>
<div class="control has-icons-left"> <div class="control has-icons-left">
<div class="select">
<select id="selectFilter--lotNameSearchType" name="lotNameSearchType">
<option value="">contains</option>
<option value="startsWith">starts with</option>
<option value="endsWith">ends with</option>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
<div class="control is-expanded">
<input class="input" id="searchFilter--lotName" name="lotName" /> <input class="input" id="searchFilter--lotName" name="lotName" />
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div> </div>
</div> </div>
<div class="column"> </form>
<div class="field">
<label class="label" for="searchFilter--lotTypeId"><%= configFunctions.getProperty("aliases.lot") %> Type</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<select id="searchFilter--lotTypeId" name="lotTypeId">
<option value="">(All <%= configFunctions.getProperty("aliases.lot") %> Types)</option>
<% for (const lotType of lotTypes) { %>
<option value="<%= lotType.lotTypeId %>"><%= lotType.lotType %></option>
<% } %>
</select>
</div>
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</div>
</div>
</div>
</div>
</form>
</div> </div>
<div id="container--searchResults"></div> <div id="container--searchResults"></div>