Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/src/dtos/listings/listings-query-body.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export class ListingsQueryBody extends PaginationAllowsAllQueryParams {
})
@IsArray({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(16, { groups: [ValidationsGroupsEnum.default] })
@Type(() => ListingFilterParams)
@IsEnum(ListingOrderByKeys, {
groups: [ValidationsGroupsEnum.default],
each: true,
Expand Down
1 change: 0 additions & 1 deletion api/src/dtos/listings/listings-query-params.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export class ListingsQueryParams extends PaginationAllowsAllQueryParams {
})
@IsArray({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(16, { groups: [ValidationsGroupsEnum.default] })
@Type(() => ListingFilterParams)
@IsEnum(ListingOrderByKeys, {
groups: [ValidationsGroupsEnum.default],
each: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import { BaseFilter } from '../shared/base-filter.dto';
import { Expose } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { ApiPropertyOptional } from '@nestjs/swagger';
import {
MultiselectQuestionsApplicationSectionEnum,
MultiselectQuestionsStatusEnum,
} from '@prisma/client';
import { BaseFilter } from '../shared/base-filter.dto';
import { MultiselectQuestionFilterKeys } from '../../enums/multiselect-questions/filter-key-enum';
import { MultiselectQuestionsApplicationSectionEnum } from '@prisma/client';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';

export class MultiselectQuestionFilterParams extends BaseFilter {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional({
example: 'uuid',
enum: MultiselectQuestionsApplicationSectionEnum,
enumName: 'MultiselectQuestionsApplicationSectionEnum',
example: 'preferences',
})
[MultiselectQuestionFilterKeys.applicationSection]?: MultiselectQuestionsApplicationSectionEnum;

@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional({
example: 'uuid',
})
[MultiselectQuestionFilterKeys.jurisdiction]?: string;

@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional({
enum: MultiselectQuestionsApplicationSectionEnum,
enumName: 'MultiselectQuestionsApplicationSectionEnum',
example: 'preferences',
enum: MultiselectQuestionsStatusEnum,
enumName: 'MultiselectQuestionsStatusEnum',
example: 'active',
})
@IsString({ groups: [ValidationsGroupsEnum.default] })
[MultiselectQuestionFilterKeys.applicationSection]?: MultiselectQuestionsApplicationSectionEnum;
[MultiselectQuestionFilterKeys.status]?: MultiselectQuestionsStatusEnum;
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { Expose, Type } from 'class-transformer';
import { Expose, Transform, Type } from 'class-transformer';
import {
ArrayMaxSize,
IsArray,
IsEnum,
IsString,
Validate,
ValidateNested,
} from 'class-validator';
import { ApiPropertyOptional, getSchemaPath } from '@nestjs/swagger';
import { MultiselectQuestionFilterParams } from './multiselect-question-filter-params.dto';
import { ArrayMaxSize, IsArray, ValidateNested } from 'class-validator';
import { PaginationAllowsAllQueryParams } from '../shared/pagination.dto';
import { SearchStringLengthCheck } from '../../decorators/search-string-length-check.decorator';
import { MultiselectQuestionOrderByKeys } from '../../enums/multiselect-questions/order-by-enum';
import { MultiselectQuestionViews } from '../../enums/multiselect-questions/view-enum';
import { OrderByEnum } from '../../enums/shared/order-by-enum';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { OrderQueryParamValidator } from '../../utilities/order-by-validator';

export class MultiselectQuestionQueryParams {
export class MultiselectQuestionQueryParams extends PaginationAllowsAllQueryParams {
@Expose()
@ApiPropertyOptional({
type: [String],
Expand All @@ -18,4 +31,65 @@ export class MultiselectQuestionQueryParams {
@Type(() => MultiselectQuestionFilterParams)
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
filter?: MultiselectQuestionFilterParams[];

@Expose()
@ApiPropertyOptional({
enum: MultiselectQuestionOrderByKeys,
enumName: 'MultiselectQuestionOrderByKeys',
example: ['status'],
default: ['status'],
isArray: true,
})
@IsArray({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(16, { groups: [ValidationsGroupsEnum.default] })
@IsEnum(MultiselectQuestionOrderByKeys, {
groups: [ValidationsGroupsEnum.default],
each: true,
})
@Validate(OrderQueryParamValidator, {
groups: [ValidationsGroupsEnum.default],
})
orderBy?: MultiselectQuestionOrderByKeys[];

@Expose()
@ApiPropertyOptional({
enum: OrderByEnum,
enumName: 'OrderByEnum',
example: ['desc'],
default: ['desc'],
isArray: true,
})
@IsArray({ groups: [ValidationsGroupsEnum.default] })
@ArrayMaxSize(16, { groups: [ValidationsGroupsEnum.default] })
@Transform(({ value }) => {
return value ? value.map((val) => val.toLowerCase()) : undefined;
})
@IsEnum(OrderByEnum, { groups: [ValidationsGroupsEnum.default], each: true })
@Validate(OrderQueryParamValidator, {
groups: [ValidationsGroupsEnum.default],
})
orderDir?: OrderByEnum[];

@Expose()
@ApiPropertyOptional({
type: String,
example: 'search',
})
@IsString({ groups: [ValidationsGroupsEnum.default] })
@SearchStringLengthCheck('search', {
message: 'Search must be at least 3 characters',
groups: [ValidationsGroupsEnum.default],
})
search?: string;

@Expose()
@ApiPropertyOptional({
enum: MultiselectQuestionViews,
enumName: 'MultiselectQuestionViews',
example: 'base',
})
@IsEnum(MultiselectQuestionViews, {
groups: [ValidationsGroupsEnum.default],
})
view?: MultiselectQuestionViews;
}
3 changes: 2 additions & 1 deletion api/src/enums/multiselect-questions/filter-key-enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum MultiselectQuestionFilterKeys {
jurisdiction = 'jurisdiction',
applicationSection = 'applicationSection',
jurisdiction = 'jurisdiction',
status = 'status',
}
6 changes: 6 additions & 0 deletions api/src/enums/multiselect-questions/order-by-enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum MultiselectQuestionOrderByKeys {
jurisdiction = 'jurisdiction',
name = 'name',
status = 'status',
updatedAt = 'updatedAt',
}
141 changes: 96 additions & 45 deletions api/src/services/multiselect-question.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import { MultiselectQuestionFilterKeys } from '../enums/multiselect-questions/fi
import { MultiselectQuestionViews } from '../enums/multiselect-questions/view-enum';
import { permissionActions } from '../enums/permissions/permission-actions-enum';
import { buildFilter } from '../utilities/build-filter';
import { buildOrderByForMultiselectQuestions } from '../utilities/build-order-by';
import { doJurisdictionHaveFeatureFlagSet } from '../utilities/feature-flag-utilities';
import { mapTo } from '../utilities/mapTo';
import { calculateSkip, calculateTake } from '../utilities/pagination-helpers';

export const includeViews: Partial<
Record<MultiselectQuestionViews, Prisma.MultiselectQuestionsInclude>
Expand Down Expand Up @@ -74,19 +76,47 @@ export class MultiselectQuestionService {
async list(
params: MultiselectQuestionQueryParams,
): Promise<MultiselectQuestion[]> {
let rawMultiselectQuestions =
const whereClause = this.buildWhere(params);

const count = await this.prisma.multiselectQuestions.count({
where: whereClause,
});

// if passed in page and limit would result in no results because there aren't that many
// multiselectQuestions revert back to the first page
let page = params.page;
if (count && params.limit && params.limit !== 'all' && params.page > 1) {
if (Math.ceil(count / params.limit) < params.page) {
page = 1;
}
}

const query = {
skip: calculateSkip(params.limit, page),
take: calculateTake(params.limit),
orderBy: buildOrderByForMultiselectQuestions(
params.orderBy,
params.orderDir,
),
where: whereClause,
};

const rawMultiselectQuestions =
await this.prisma.multiselectQuestions.findMany({
include: includeViews.fundamentals,
where: this.buildWhere(params),
...query,
include: includeViews[params.view ?? 'fundamentals'],
});

rawMultiselectQuestions = rawMultiselectQuestions.map((msq) => {
return {
...msq,
jurisdictions: [msq.jurisdiction],
};
});
return mapTo(MultiselectQuestion, rawMultiselectQuestions);
// TODO: Can be removed after MSQ refactor
const multiselectQuestionsWithJurisdictions = rawMultiselectQuestions.map(
(msq) => {
return {
...msq,
jurisdictions: [msq.jurisdiction],
};
},
);
return mapTo(MultiselectQuestion, multiselectQuestionsWithJurisdictions);
}

/*
Expand All @@ -96,42 +126,63 @@ export class MultiselectQuestionService {
params: MultiselectQuestionQueryParams,
): Prisma.MultiselectQuestionsWhereInput {
const filters: Prisma.MultiselectQuestionsWhereInput[] = [];
if (!params?.filter?.length) {
return {
AND: filters,
};
if (params?.filter?.length) {
params.filter.forEach((filter) => {
if (filter[MultiselectQuestionFilterKeys.applicationSection]) {
const builtFilter = buildFilter({
$comparison: filter.$comparison,
$include_nulls: false,
value: filter[MultiselectQuestionFilterKeys.applicationSection],
key: MultiselectQuestionFilterKeys.applicationSection,
caseSensitive: true,
});
filters.push({
OR: builtFilter.map((filt) => ({
applicationSection: filt,
})),
});
} else if (filter[MultiselectQuestionFilterKeys.jurisdiction]) {
const builtFilter = buildFilter({
$comparison: filter.$comparison,
$include_nulls: false,
value: filter[MultiselectQuestionFilterKeys.jurisdiction],
key: MultiselectQuestionFilterKeys.jurisdiction,
caseSensitive: true,
});
filters.push({
OR: builtFilter.map((filt) => ({
jurisdiction: {
id: filt,
},
})),
});
} else if (filter[MultiselectQuestionFilterKeys.status]) {
console.log(filter[MultiselectQuestionFilterKeys.status]);
const builtFilter = buildFilter({
$comparison: filter.$comparison,
$include_nulls: false,
value: filter[MultiselectQuestionFilterKeys.status],
key: MultiselectQuestionFilterKeys.status,
caseSensitive: true,
});
filters.push({
OR: builtFilter.map((filt) => ({
status: filt,
})),
});
}
});
}
params.filter.forEach((filter) => {
if (filter[MultiselectQuestionFilterKeys.jurisdiction]) {
const builtFilter = buildFilter({
$comparison: filter.$comparison,
$include_nulls: false,
value: filter[MultiselectQuestionFilterKeys.jurisdiction],
key: MultiselectQuestionFilterKeys.jurisdiction,
caseSensitive: true,
});
filters.push({
OR: builtFilter.map((filt) => ({
jurisdiction: {
id: filt,
},
})),
});
} else if (filter[MultiselectQuestionFilterKeys.applicationSection]) {
const builtFilter = buildFilter({
$comparison: filter.$comparison,
$include_nulls: false,
value: filter[MultiselectQuestionFilterKeys.applicationSection],
key: MultiselectQuestionFilterKeys.applicationSection,
caseSensitive: true,
});
filters.push({
OR: builtFilter.map((filt) => ({
applicationSection: filt,
})),
});
}
});

if (params?.search) {
filters.push({
name: {
contains: params.search,
mode: Prisma.QueryMode.insensitive,
},
});
}

return {
AND: filters,
};
Expand Down
Loading
Loading