Skip to content

Commit

Permalink
feat: filter project by status, type, with and or toggle
Browse files Browse the repository at this point in the history
  • Loading branch information
steveoh committed Nov 26, 2024
1 parent 69fc2c9 commit d1a468f
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 31 deletions.
8 changes: 4 additions & 4 deletions src/components/definitionExpressionManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,17 @@ describe('createDefinitionExpression', () => {
it('should use the user input join value intersect when selecting feature types with and', () => {
const state: State = {
projects: all,
features: new Set<Key>(['Fence', 'Dam']),
features: new Set<Key>(['Fish passage structure', 'Dam']),
join: and,
};
const result = generateDefinitionExpression(state);

expect(result).toEqual({
centroids:
"((Project_ID in(select Project_ID from POINT where TypeDescription='Dam' intersect Project_ID in(select Project_ID from POINT where TypeDescription='Fence')))",
'Project_ID in(select Project_ID from POINT where TypeCode=9 intersect select Project_ID from LINE where TypeCode=12)',
point:
"(Project_ID in(select Project_ID from POINT where TypeDescription='Dam' intersect Project_ID in(select Project_ID from POINT where TypeDescription='Fence')))",
line: '1=0',
'TypeCode in(9) and Project_ID in(select Project_ID from POINT where TypeCode=9 intersect select Project_ID from LINE where TypeCode=12)',
line: 'TypeCode in(12) and Project_ID in(select Project_ID from POINT where TypeCode=9 intersect select Project_ID from LINE where TypeCode=12)',
poly: '1=0',
});
});
Expand Down
137 changes: 110 additions & 27 deletions src/components/definitionExpressionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import { featureTypes, projectStatus } from './data/filters';
const allRecords = '';
const noRecords = '1=0' as const;
const all = 'all' as const;
const and = 'and' as const;
const or = 'or' as const;
const addPossibleConjunction = (phrase: string) => {
if (!phrase || [allRecords, noRecords].includes(phrase)) {
return phrase;
}

return `${phrase} and `;
};

const full = featureTypes.reduce(
(acc, { type }) => {
Expand Down Expand Up @@ -67,22 +73,22 @@ const generateExpressions = (
projectPredicate: string,
featurePredicates: Record<
'point' | 'line' | 'poly',
{
code: number;
type: string;
}[]
| {
code: number;
type: string;
}[]
| string
>,
join: 'and' | 'or',
) => {
// if the join style is or, we can use sql in statements for each table
if (join === or) {
const result = {
centroids: '',
point: '',
line: '',
poly: '',
};
const result = {
centroids: '',
point: '',
line: '',
poly: '',
};

if (join === or) {
// if there is a project status filter, we can use it for all tables
if (projectPredicate) {
const featureStatusExpression = `StatusDescription in(${projectPredicate})`;
Expand All @@ -95,13 +101,11 @@ const generateExpressions = (

const expressions = [];

if ((featurePredicates?.point ?? 0).length) {
if (Array.isArray(featurePredicates.point)) {
if (featurePredicates.point.length === full.point) {
result.point = allRecords;
} else {
if (result.point) {
result.point += ' and ';
}
result.point = addPossibleConjunction(result.point);

const codes = featurePredicates.point.map(({ code }) => code).join(',');

Expand All @@ -112,13 +116,11 @@ const generateExpressions = (
result.point = typeof featurePredicates?.point === 'string' ? result.point : '1=0';
}

if ((featurePredicates?.line ?? 0).length) {
if (Array.isArray(featurePredicates.line)) {
if (featurePredicates.line.length === full.line) {
result.point = allRecords;
} else {
if (result.line) {
result.line += ' and ';
}
result.line = addPossibleConjunction(result.line);

const codes = featurePredicates.line.map(({ code }) => code).join(',');

Expand All @@ -129,13 +131,11 @@ const generateExpressions = (
result.line = typeof featurePredicates?.line === 'string' ? result.line : '1=0';
}

if ((featurePredicates?.poly ?? 0).length) {
if (Array.isArray(featurePredicates.poly)) {
if (featurePredicates.poly.length === full.poly) {
result.point = allRecords;
} else {
if (result.poly) {
result.poly += ' and ';
}
result.poly = addPossibleConjunction(result.poly);

const codes = featurePredicates.poly.map(({ code }) => code).join(',');

Expand All @@ -152,7 +152,7 @@ const generateExpressions = (

if (result.centroids) {
if (expressions.length > 0) {
result.centroids += ' and ';
result.centroids = addPossibleConjunction(result.centroids);
}

if (expressions.length === 1) {
Expand All @@ -168,6 +168,90 @@ const generateExpressions = (

result.centroids += `Project_ID in(${expressions.join(` union `)})`;

return result;
} else {
if (projectPredicate) {
const featureStatusExpression = `StatusDescription in(${projectPredicate})`;

result.centroids = `Status in(${projectPredicate})`;
result.point = featureStatusExpression;
result.line = featureStatusExpression;
result.poly = featureStatusExpression;
}

const expressions = [];

if (Array.isArray(featurePredicates.point)) {
result.point = addPossibleConjunction(result.point);

const predicate = featurePredicates.point
.map(({ code }) => `select Project_ID from POINT where TypeCode=${code}`)
.join(' intersect ');

expressions.push(predicate);
result.point += `TypeCode in${featurePredicates.point.map(({ code }) => `(${code})`).join(',')}`;
} else {
result.point = typeof featurePredicates?.point === 'string' ? result.point : '1=0';
}

if (Array.isArray(featurePredicates.line)) {
result.line = addPossibleConjunction(result.line);

const predicate = featurePredicates.line
.map(({ code }) => `select Project_ID from LINE where TypeCode=${code}`)
.join(' intersect ');

expressions.push(predicate);
result.line += `TypeCode in${featurePredicates.line.map(({ code }) => `(${code})`).join(',')}`;
} else {
result.line = typeof featurePredicates?.line === 'string' ? result.line : '1=0';
}

if (Array.isArray(featurePredicates.poly)) {
result.poly = addPossibleConjunction(result.poly);

const predicate = featurePredicates.poly
.map(({ code }) => `select Project_ID from POLY where TypeCode=${code}`)
.join(' intersect ');

expressions.push(predicate);
result.poly += `TypeCode in${featurePredicates.poly.map(({ code }) => `(${code})`).join(',')}`;
} else {
result.poly = typeof featurePredicates?.poly === 'string' ? result.poly : '1=0';
}

if (expressions.length === 0) {
return result;
}

result.centroids = addPossibleConjunction(result.centroids);
result.point = addPossibleConjunction(result.point);
result.line = addPossibleConjunction(result.line);
result.poly = addPossibleConjunction(result.poly);

if (expressions.length === 1) {
const projectExpression = `Project_ID in(${expressions[0]})`;
result.centroids += projectExpression;
result.point += projectExpression;
result.line += projectExpression;
result.poly += projectExpression;

return result;
}

const expression = `Project_ID in(${expressions.join(` intersect `)})`;
result.centroids += expression;

if (result.point && result.point != noRecords) {
result.point += expression;
}
if (result.line && result.line != noRecords) {
result.line += expression;
}
if (result.poly && result.poly != noRecords) {
result.poly += expression;
}

return result;
}
};
Expand All @@ -194,7 +278,6 @@ export const generateDefinitionExpression = ({
};
}

// empty set mean no filters so no records can be matched
if (
projectPredicate === allRecords &&
Object.entries(featurePredicates).every(([key, value]) => value.length === full[key as keyof typeof full])
Expand Down

0 comments on commit d1a468f

Please sign in to comment.