Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hub-common): hubSearchEvents switch to new POST events search route #1787

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { unique } from "../../../util";
import { IFilter } from "../../types/IHubCatalog";
import { getPredicateValuesByKey } from "./getPredicateValuesByKey";

export const getUniquePredicateValuesByKey = <T>(
filters: IFilter[],
predicateKey: string
): T[] => {
return getPredicateValuesByKey<T>(filters, predicateKey).filter(unique);
};
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
import { IFilter } from "../../types/IHubCatalog";
import {
EventAccess,
EventAssociationEntityType,
EventAttendanceType,
EventStatus,
GetEventsParams,
ISearchEvents,
} from "../../../events/api/orval/api/orval-events";
import { getOptionalPredicateStringsByKey } from "./getOptionalPredicateStringsByKey";
import { getPredicateValuesByKey } from "./getPredicateValuesByKey";
import { getUniquePredicateValuesByKey } from "./getUniquePredicateValuesByKey";
import { IDateRange } from "../../types/types";
import { searchGroups } from "@esri/arcgis-rest-portal";
import { IHubRequestOptions } from "../../../types";
import { isUpdateGroup } from "../../../utils/is-update-group";
import { toEnums } from "./toEnumConverters";

/**
* Builds a Partial<GetEventsParams> given an Array of IFilter objects
* Builds a Partial<ISearchEvents> given an Array of IFilter objects
* @param filters An Array of IFilter
* @returns a Partial<GetEventsParams> for the given Array of IFilter objects
* @returns a Partial<ISearchEvents> for the given Array of IFilter objects
*/
export async function processFilters(
filters: IFilter[],
requestOptions: IHubRequestOptions
): Promise<Partial<GetEventsParams>> {
const processedFilters: Partial<GetEventsParams> = {};
const access = getOptionalPredicateStringsByKey(filters, "access");
if (access?.length) {
processedFilters.access = access;
): Promise<Partial<ISearchEvents>> {
const processedFilters: Partial<ISearchEvents> = {};
const access = getUniquePredicateValuesByKey<string>(filters, "access");
if (access.length) {
processedFilters.access = toEnums(access, EventAccess);
}
const canEdit = getPredicateValuesByKey<boolean>(filters, "canEdit");
if (canEdit.length) {
processedFilters.canEdit = canEdit[0].toString();
processedFilters.canEdit = canEdit[0];
}
const entityIds = getOptionalPredicateStringsByKey(filters, "entityId");
if (entityIds?.length) {
const entityIds = getUniquePredicateValuesByKey<string>(filters, "entityId");
if (entityIds.length) {
processedFilters.entityIds = entityIds;
}
const entityTypes = getOptionalPredicateStringsByKey(filters, "entityType");
if (entityTypes?.length) {
processedFilters.entityTypes = entityTypes;
const entityTypes = getUniquePredicateValuesByKey<string>(
filters,
"entityType"
);
if (entityTypes.length) {
processedFilters.entityTypes = toEnums(
entityTypes,
EventAssociationEntityType
);
}
const eventIds = getOptionalPredicateStringsByKey(filters, "id");
if (eventIds?.length) {
const eventIds = getUniquePredicateValuesByKey<string>(filters, "id");
if (eventIds.length) {
processedFilters.eventIds = eventIds;
}
const term = getPredicateValuesByKey<string>(filters, "term");
Expand All @@ -48,40 +58,46 @@ export async function processFilters(
if (orgId.length) {
processedFilters.orgId = orgId[0];
}
const categories = getOptionalPredicateStringsByKey(filters, "categories");
if (categories?.length) {
const categories = getUniquePredicateValuesByKey<string>(
filters,
"categories"
);
if (categories.length) {
processedFilters.categories = categories;
}
const tags = getOptionalPredicateStringsByKey(filters, "tags");
if (tags?.length) {
const tags = getUniquePredicateValuesByKey<string>(filters, "tags");
if (tags.length) {
processedFilters.tags = tags;
}
const groupIds = getOptionalPredicateStringsByKey(filters, "group");
const groupIds = getUniquePredicateValuesByKey<string>(filters, "group");
// if a group was provided, we prioritize that over individual readGroupId or editGroupId
// filters to prevent collisions
if (groupIds?.length) {
if (groupIds.length) {
// We are explicitly sending groupIds to sharedToGroups
processedFilters.sharedToGroups = groupIds;
} else {
// individual readGroupId & editGroupId filters
const readGroupIds = getOptionalPredicateStringsByKey(
const readGroupIds = getUniquePredicateValuesByKey<string>(
filters,
"readGroupId"
);
if (readGroupIds?.length) {
if (readGroupIds.length) {
processedFilters.readGroups = readGroupIds;
}
const editGroupIds = getOptionalPredicateStringsByKey(
const editGroupIds = getUniquePredicateValuesByKey<string>(
filters,
"editGroupId"
);
if (editGroupIds?.length) {
if (editGroupIds.length) {
processedFilters.editGroups = editGroupIds;
}
}
// NOTE: previously notGroup was an inverse of group, but now they are subtly different
// We do not yet have an inverse of sharedToGroups.
const notGroupIds = getPredicateValuesByKey<string>(filters, "notGroup");
const notGroupIds = getUniquePredicateValuesByKey<string>(
filters,
"notGroup"
);
// if a notGroup was provided, we prioritize that over individual notReadGroupId or notEditGroupId
// filters to prevent collisions
if (notGroupIds.length) {
Expand All @@ -100,45 +116,47 @@ export async function processFilters(
{ notReadGroupIds: [], notEditGroupIds: [] }
);
if (notReadGroupIds.length) {
processedFilters.withoutReadGroups = notReadGroupIds.join(",");
processedFilters.withoutReadGroups = notReadGroupIds;
}
if (notEditGroupIds.length) {
processedFilters.withoutEditGroups = notEditGroupIds.join(",");
processedFilters.withoutEditGroups = notEditGroupIds;
}
} else {
// individual notReadGroupId & notEditGroupId filters
const notReadGroupIds = getOptionalPredicateStringsByKey(
const notReadGroupIds = getUniquePredicateValuesByKey<string>(
filters,
"notReadGroupId"
);
if (notReadGroupIds?.length) {
if (notReadGroupIds.length) {
processedFilters.withoutReadGroups = notReadGroupIds;
}
const notEditGroupIds = getOptionalPredicateStringsByKey(
const notEditGroupIds = getUniquePredicateValuesByKey<string>(
filters,
"notEditGroupId"
);
if (notEditGroupIds?.length) {
if (notEditGroupIds.length) {
processedFilters.withoutEditGroups = notEditGroupIds;
}
}
const attendanceType = getOptionalPredicateStringsByKey(
const attendanceType = getUniquePredicateValuesByKey<string>(
filters,
"attendanceType"
);
if (attendanceType?.length) {
processedFilters.attendanceTypes = attendanceType;
if (attendanceType.length) {
processedFilters.attendanceTypes = toEnums(
attendanceType,
EventAttendanceType
);
}
const createdByIds = getOptionalPredicateStringsByKey(filters, "owner");
if (createdByIds?.length) {
const createdByIds = getUniquePredicateValuesByKey<string>(filters, "owner");
if (createdByIds.length) {
processedFilters.createdByIds = createdByIds;
}
const status = getOptionalPredicateStringsByKey(filters, "status");
processedFilters.status = status?.length
? status
: [EventStatus.PLANNED, EventStatus.CANCELED]
.map((val) => val.toLowerCase())
.join(",");
const status = getUniquePredicateValuesByKey<string>(filters, "status");
processedFilters.status = status.length
? toEnums(status, EventStatus)
: [EventStatus.PLANNED, EventStatus.CANCELED];

const startDateRange = getPredicateValuesByKey<IDateRange<string | number>>(
filters,
"startDateRange"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { IHubSearchOptions } from "../../types/IHubSearchOptions";
import {
EventSort,
GetEventsParams,
ISearchEvents,
EventSortOrder,
} from "../../../events/api/orval/api/orval-events";

/**
* Builds a Partial<GetEventsParams> for the given IHubSearchOptions
* Builds a Partial<ISearchEvents> for the given IHubSearchOptions
* @param options An IHubSearchOptions object
* @returns a Partial<GetEventsParams> for the given IHubSearchOptions
* @returns a Partial<ISearchEvents> for the given IHubSearchOptions
*/
export function processOptions(
options: IHubSearchOptions
): Partial<GetEventsParams> {
const processedOptions: Partial<GetEventsParams> = {};
): Partial<ISearchEvents> {
const processedOptions: Partial<ISearchEvents> = {};
if (options.num > 0) {
processedOptions.num = options.num.toString();
processedOptions.num = options.num;
}
if (options.start > 1) {
processedOptions.start = options.start.toString();
processedOptions.start = options.start;
}
if (options.sortField === "modified") {
processedOptions.sortBy = EventSort.updatedAt;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Converts a string to an enum value
*
* strings not in the enum will be returned as the original string
*/
export function toEnum<T>(value: string, enumType: T): T[keyof T] {
return (
(enumType as any)[value] ||
(enumType as any)[value.toUpperCase()] ||
(enumType as any)[value.toLowerCase()] ||
value
);
}

/**
* Converts an array of strings to an array of enum values
*
* strings not in the enum will be returned as the original string
*/
export function toEnums<T>(values: string[], enumType: T): Array<T[keyof T]> {
return values.map((value) => toEnum<T>(value, enumType));
}
17 changes: 10 additions & 7 deletions packages/common/src/search/_internal/hubSearchEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ import { IQuery } from "../types/IHubCatalog";
import { IHubSearchOptions } from "../types/IHubSearchOptions";
import { IHubSearchResponse } from "../types/IHubSearchResponse";
import { IHubSearchResult } from "../types/IHubSearchResult";
import { getEvents } from "../../events/api/events";
import { GetEventsParams } from "../../events/api/orval/api/orval-events";
import { searchEvents } from "../../events/api/events";
import {
GetEventsInclude,
GetEventsParams,
ISearchEvents,
} from "../../events/api/orval/api/orval-events";
import { eventToSearchResult } from "./hubEventsHelpers/eventToSearchResult";
import { processOptions } from "./hubEventsHelpers/processOptions";
import { processFilters } from "./hubEventsHelpers/processFilters";

/**
* Searches for events against the Events 3 API using the given `query` and `options`.
* Currently supported filters include:
* - access: 'public' | 'private' | 'org' | Array<'public' | 'org' | 'access'>;
* - access: 'public' | 'private' | 'org' | Array<'public' | 'org' | 'private'>;
* - canEdit: boolean
* - entityId: string | string[];
* - entityType: string | string[];
* - id: string | string[];
* - userId: string;
* - term: string;
* - categories: string | string[];
* - tags: string | string[];
Expand Down Expand Up @@ -54,12 +57,12 @@ export async function hubSearchEvents(
options.requestOptions
);
const processedOptions = processOptions(options);
const data: GetEventsParams = {
const data: ISearchEvents = {
...processedFilters,
...processedOptions,
include: "creator,location",
include: [GetEventsInclude.creator, GetEventsInclude.location],
};
const { items, nextStart, total } = await getEvents({
const { items, nextStart, total } = await searchEvents({
...options.requestOptions,
data,
});
Expand Down
Loading