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

Presentation: Enforce result paging for hierarchy compare #678

Merged
merged 9 commits into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 3 additions & 3 deletions common/api/presentation-backend.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { DistinctValuesRequestOptions } from '@bentley/presentation-common';
import { EventSink } from '@bentley/imodeljs-backend';
import { ExtendedContentRequestOptions } from '@bentley/presentation-common';
import { ExtendedHierarchyRequestOptions } from '@bentley/presentation-common';
import { HierarchyCompareInfo } from '@bentley/presentation-common';
import { HierarchyRequestOptions } from '@bentley/presentation-common';
import { Id64String } from '@bentley/bentleyjs-core';
import { IDisposable } from '@bentley/bentleyjs-core';
Expand All @@ -32,7 +33,6 @@ import { NodeKey } from '@bentley/presentation-common';
import { NodePathElement } from '@bentley/presentation-common';
import { Paged } from '@bentley/presentation-common';
import { PagedResponse } from '@bentley/presentation-common';
import { PartialHierarchyModification } from '@bentley/presentation-common';
import { PresentationDataCompareOptions } from '@bentley/presentation-common';
import { PresentationUnitSystem } from '@bentley/presentation-common';
import { RegisteredRuleset } from '@bentley/presentation-common';
Expand Down Expand Up @@ -155,9 +155,9 @@ export class PresentationManager {
activeLocale: string | undefined;
activeUnitSystem: PresentationUnitSystem | undefined;
// @deprecated (undocumented)
compareHierarchies(requestContext: ClientRequestContext, requestOptions: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<PartialHierarchyModification[]>;
compareHierarchies(requestContext: ClientRequestContext, requestOptions: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<HierarchyCompareInfo>;
pmconne marked this conversation as resolved.
Show resolved Hide resolved
// @beta
compareHierarchies(requestOptions: WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>): Promise<PartialHierarchyModification[]>;
compareHierarchies(requestOptions: WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>): Promise<HierarchyCompareInfo>;
// @deprecated
computeSelection(requestContext: ClientRequestContext, requestOptions: SelectionScopeRequestOptions<IModelDb>, ids: Id64String[], scopeId: string): Promise<KeySet>;
// @beta
Expand Down
41 changes: 38 additions & 3 deletions common/api/presentation-common.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,34 @@ export enum GroupingSpecificationTypes {
SameLabelInstance = "SameLabelInstance"
}

// @alpha (undocumented)
export interface HierarchyCompareInfo {
// (undocumented)
changes: PartialHierarchyModification[];
// (undocumented)
nextStep?: {
prevHierarchyNode: string;
currHierarchyNode: string;
};
}

// @alpha (undocumented)
export namespace HierarchyCompareInfo {
export function fromJSON(json: HierarchyCompareInfoJSON): HierarchyCompareInfo;
export function toJSON(obj: HierarchyCompareInfo): HierarchyCompareInfoJSON;
}

// @alpha (undocumented)
export interface HierarchyCompareInfoJSON {
// (undocumented)
changes: PartialHierarchyModificationJSON[];
// (undocumented)
nextStep?: {
prevHierarchyNode: string;
currHierarchyNode: string;
};
}

// @public
export interface HierarchyRequestOptions<TIModel> extends RequestOptionsWithRuleset<TIModel> {
}
Expand Down Expand Up @@ -1530,6 +1558,13 @@ export interface PresentationDataCompareOptions<TIModel, TNodeKey> extends Reque
rulesetOrId?: Ruleset | string;
rulesetVariables?: RulesetVariable[];
};
// (undocumented)
resultSetSize?: number;
// (undocumented)
startPosition?: {
prevHierarchyNode: string;
currHierarchyNode: string;
};
}

// @alpha
Expand All @@ -1548,8 +1583,8 @@ export enum PresentationRpcEvents {

// @public
export class PresentationRpcInterface extends RpcInterface {
// @alpha
compareHierarchies(_token: IModelRpcProps, _options: PresentationDataCompareRpcOptions): PresentationRpcResponse<PartialHierarchyModificationJSON[]>;
// @alpha (undocumented)
compareHierarchies(_token: IModelRpcProps, _options: PresentationDataCompareRpcOptions): PresentationRpcResponse<HierarchyCompareInfoJSON>;
// (undocumented)
computeSelection(_token: IModelRpcProps, _options: SelectionScopeRpcRequestOptions, _ids: Id64String[], _scopeId: string): PresentationRpcResponse<KeySetJSON>;
// @deprecated (undocumented)
Expand Down Expand Up @@ -2069,7 +2104,7 @@ export class RpcRequestsHandler implements IDisposable {
constructor(props?: RpcRequestsHandlerProps);
readonly clientId: string;
// (undocumented)
compareHierarchies(options: PresentationDataCompareOptions<IModelRpcProps, NodeKeyJSON>): Promise<PartialHierarchyModificationJSON[]>;
compareHierarchies(options: PresentationDataCompareOptions<IModelRpcProps, NodeKeyJSON>): Promise<HierarchyCompareInfoJSON>;
// (undocumented)
computeSelection(options: SelectionScopeRequestOptions<IModelRpcProps>, ids: Id64String[], scopeId: string): Promise<KeySetJSON>;
// (undocumented)
Expand Down
3 changes: 3 additions & 0 deletions common/api/summary/presentation-common.exports.csv
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ public;GroupingRule
public;GroupingSpecification = ClassGroup | PropertyGroup | SameLabelInstanceGroup
public;GroupingSpecificationBase
public;GroupingSpecificationTypes
alpha;HierarchyCompareInfo
alpha;HierarchyCompareInfo
alpha;HierarchyCompareInfoJSON
public;HierarchyRequestOptions
public;HierarchyRpcRequestOptions = PresentationRpcRequestOptions
alpha;HierarchyUpdateInfo = typeof UPDATE_FULL | PartialHierarchyModification[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-backend",
"comment": "Enforce max result set size for hierarchy compare.",
"type": "none"
}
],
"packageName": "@bentley/presentation-backend",
"email": "24278440+saskliutas@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-common",
"comment": "Added HierarchyCompareInfo object that describes hierarchy changes and next step from which comparison should be continued.",
"type": "none"
}
],
"packageName": "@bentley/presentation-common",
"email": "24278440+saskliutas@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@bentley/presentation-frontend",
"comment": "Changed 'compareHierarchy' to build result in pages for massive result sets. ",
"type": "none"
}
],
"packageName": "@bentley/presentation-frontend",
"email": "24278440+saskliutas@users.noreply.github.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import { BriefcaseDb, EventSink, IModelDb, IModelHost, IModelJsNative } from "@b
import {
Content, ContentDescriptorRequestOptions, ContentFlags, ContentRequestOptions, DefaultContentDisplayTypes, Descriptor, DescriptorOverrides,
DisplayLabelRequestOptions, DisplayLabelsRequestOptions, DisplayValueGroup, DistinctValuesRequestOptions, ExtendedContentRequestOptions,
ExtendedHierarchyRequestOptions, getLocalesDirectory, HierarchyRequestOptions, InstanceKey, KeySet, LabelDefinition, LabelRequestOptions, Node,
NodeKey, NodePathElement, Paged, PagedResponse, PartialHierarchyModification, PresentationDataCompareOptions, PresentationError, PresentationStatus,
ExtendedHierarchyRequestOptions, getLocalesDirectory, HierarchyCompareInfo, HierarchyRequestOptions, InstanceKey, KeySet, LabelDefinition, LabelRequestOptions, Node,
NodeKey, NodePathElement, Paged, PagedResponse, PresentationDataCompareOptions, PresentationError, PresentationStatus,
PresentationUnitSystem, RequestPriority, Ruleset, SelectionInfo, SelectionScope, SelectionScopeRequestOptions,
} from "@bentley/presentation-common";
import { PresentationBackendLoggerCategory } from "./BackendLoggerCategory";
Expand Down Expand Up @@ -848,20 +848,20 @@ export class PresentationManager {
}

/** @deprecated Use an overload with one argument */
public async compareHierarchies(requestContext: ClientRequestContext, requestOptions: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<PartialHierarchyModification[]>;
public async compareHierarchies(requestContext: ClientRequestContext, requestOptions: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<HierarchyCompareInfo>;
/**
* Compares two hierarchies specified in the request options
* TODO: Return results in pages
* @beta
*/
public async compareHierarchies(requestOptions: WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>): Promise<PartialHierarchyModification[]>;
public async compareHierarchies(requestContextOrOptions: ClientRequestContext | WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>, deprecatedRequestOptions?: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<PartialHierarchyModification[]> {
public async compareHierarchies(requestOptions: WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>): Promise<HierarchyCompareInfo>;
public async compareHierarchies(requestContextOrOptions: ClientRequestContext | WithClientRequestContext<PresentationDataCompareOptions<IModelDb, NodeKey>>, deprecatedRequestOptions?: PresentationDataCompareOptions<IModelDb, NodeKey>): Promise<HierarchyCompareInfo> {
if (requestContextOrOptions instanceof ClientRequestContext) {
return this.compareHierarchies({ ...deprecatedRequestOptions!, requestContext: requestContextOrOptions });
}

if (!requestContextOrOptions.prev.rulesetOrId && !requestContextOrOptions.prev.rulesetVariables)
return [];
return { changes: [] };

const { strippedOptions: { prev, rulesetVariables, ...options } } = this.registerRuleset(requestContextOrOptions);

Expand All @@ -882,7 +882,7 @@ export class PresentationManager {
currRulesetVariables: JSON.stringify(currRulesetVariables),
expandedNodeKeys: JSON.stringify(options.expandedNodeKeys ?? []),
};
return this.request(params, (key: string, value: any) => ((key === "") ? value.map(PartialHierarchyModification.fromJSON) : value));
return this.request(params, (key: string, value: any) => ((key === "") ? HierarchyCompareInfo.fromJSON(value) : value));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@ import { IModelRpcProps } from "@bentley/imodeljs-common";
import {
ContentDescriptorRpcRequestOptions, ContentJSON, ContentRpcRequestOptions, Descriptor, DescriptorJSON, DescriptorOverrides, DiagnosticsOptions,
DiagnosticsScopeLogs, DisplayLabelRpcRequestOptions, DisplayLabelsRpcRequestOptions, DisplayValueGroup, DisplayValueGroupJSON,
DistinctValuesRpcRequestOptions, ExtendedContentRpcRequestOptions, ExtendedHierarchyRpcRequestOptions, HierarchyRpcRequestOptions, InstanceKey,
InstanceKeyJSON, isContentDescriptorRequestOptions, isDisplayLabelRequestOptions, isExtendedContentRequestOptions,
DistinctValuesRpcRequestOptions, ExtendedContentRpcRequestOptions, ExtendedHierarchyRpcRequestOptions, HierarchyCompareInfo, HierarchyCompareInfoJSON,
HierarchyRpcRequestOptions, InstanceKey, InstanceKeyJSON, isContentDescriptorRequestOptions, isDisplayLabelRequestOptions, isExtendedContentRequestOptions,
isExtendedHierarchyRequestOptions, ItemJSON, KeySet, KeySetJSON, LabelDefinition, LabelDefinitionJSON, LabelRpcRequestOptions, Node, NodeJSON,
NodeKey, NodeKeyJSON, NodePathElement, NodePathElementJSON, Paged, PagedResponse, PageOptions, PartialHierarchyModification,
PartialHierarchyModificationJSON, PresentationDataCompareRpcOptions, PresentationError, PresentationRpcInterface, PresentationRpcResponse,
PresentationStatus, Ruleset, SelectionInfo, SelectionScope, SelectionScopeRpcRequestOptions,
NodeKey, NodeKeyJSON, NodePathElement, NodePathElementJSON, Paged, PagedResponse, PageOptions, PresentationDataCompareRpcOptions, PresentationError,
PresentationRpcInterface, PresentationRpcResponse, PresentationStatus, Ruleset, SelectionInfo, SelectionScope, SelectionScopeRpcRequestOptions,
} from "@bentley/presentation-common";
import { PresentationBackendLoggerCategory } from "./BackendLoggerCategory";
import { Presentation } from "./Presentation";
Expand Down Expand Up @@ -357,25 +356,31 @@ export class PresentationRpcImpl extends PresentationRpcInterface {
});
}

public async compareHierarchies(token: IModelRpcProps, requestOptions: PresentationDataCompareRpcOptions): PresentationRpcResponse<PartialHierarchyModificationJSON[]> {
public async compareHierarchies(token: IModelRpcProps, requestOptions: PresentationDataCompareRpcOptions): PresentationRpcResponse<HierarchyCompareInfoJSON> {
return this.makeRequest(token, "compareHierarchies", requestOptions, async (options) => {
options = {
...options,
...(options.expandedNodeKeys ? { expandedNodeKeys: options.expandedNodeKeys.map(NodeKey.fromJSON) } : undefined),
resultSetSize: getValidPageSize(requestOptions.resultSetSize),
};
const result = await this.getManager(requestOptions.clientId).compareHierarchies(options);
return result.map(PartialHierarchyModification.toJSON);
return HierarchyCompareInfo.toJSON(result);
});
}
}

const enforceValidPageSize = <TOptions extends Paged<object>>(requestOptions: TOptions): TOptions & { paging: PageOptions } => {
const requestedPageSize = requestOptions.paging?.size ?? 0;
if (requestedPageSize === 0 || requestedPageSize > MAX_ALLOWED_PAGE_SIZE)
return { ...requestOptions, paging: { ...requestOptions.paging, size: MAX_ALLOWED_PAGE_SIZE } };
const validPageSize = getValidPageSize(requestOptions.paging?.size);
if (!requestOptions.paging || requestOptions.paging.size !== validPageSize)
return { ...requestOptions, paging: { ...requestOptions.paging, size: validPageSize } };
return requestOptions as (TOptions & { paging: PageOptions });
};

const getValidPageSize = (size: number | undefined) => {
const requestedSize = size ?? 0;
return (requestedSize === 0 || requestedSize > MAX_ALLOWED_PAGE_SIZE) ? MAX_ALLOWED_PAGE_SIZE : requestedSize;
};

const nodeKeyFromJson = (json: NodeKeyJSON | undefined): NodeKey | undefined => {
if (!json)
return undefined;
Expand Down
Loading