Skip to content

Commit

Permalink
feat(hub-common): hubSearchEvents switch to new POST events search ro…
Browse files Browse the repository at this point in the history
…ute (#1787)
  • Loading branch information
velveetachef authored Jan 31, 2025
1 parent fa51064 commit 8fbb944
Show file tree
Hide file tree
Showing 9 changed files with 293 additions and 132 deletions.
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

0 comments on commit 8fbb944

Please sign in to comment.