UNPKG

@itwin/presentation-shared

Version:

The package contains types and utilities used across different iTwin.js Presentation packages.

140 lines 7.43 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.createRelationshipPathJoinClause = createRelationshipPathJoinClause; const Metadata_js_1 = require("../Metadata.js"); const ECSqlValueSelectorSnippets_js_1 = require("./ECSqlValueSelectorSnippets.js"); /** * Creates an ECSQL JOIN snippet for given relationships' path. * * Possible results: * - When the relationship is represented by a navigation property on either source or target: * ```SQL * INNER JOIN [target_schema_name].[target_class_name] [target_alias] ON [target_alias].[navigation_property_name].[Id] = [source_alias].[ECInstanceId] * ``` * - When outer joining through a non-navigation-property relationship: * ```SQL * LEFT JOIN ( * SELECT [relationship_alias].* * FROM [relationship_schema_name].[relationship_class_name] [relationship_alias] * INNER JOIN [target_schema_name].[target_class_name] [target_alias] ON [target_alias].[ECInstanceId] = [relationship_alias].[TargetECInstanceId] * ) [relationship_alias] * LEFT JOIN [target_schema_name].[target_class_name] [target_alias] ON [target_alias].[ECInstanceId] = [relationship_alias].[TargetECInstanceId] * ``` * - When inner joining through a non-navigation-property relationship: * ```SQL * INNER JOIN [relationship_schema_name].[relationship_class_name] [relationship_alias] ON [relationship_alias].[SourceECInstanceId] = [source_alias].[ECInstanceId] * INNER JOIN [target_schema_name].[target_class_name] [target_alias] ON [target_alias].[ECInstanceId] = [relationship_alias].[TargetECInstanceId] * ``` * @public */ async function createRelationshipPathJoinClause(props) { if (props.path.length === 0) { return ""; } let prev = { alias: props.path[0].sourceAlias, joinPropertyName: "ECInstanceId", className: props.path[0].sourceClassName, }; let clause = ""; for (const stepDef of props.path) { const step = await getRelationshipPathStepClasses(props.schemaProvider, stepDef); const navigationProperty = await getNavigationProperty(step); if (navigationProperty) { const isNavigationPropertyForward = navigationProperty.direction === "Forward"; const relationshipJoinPropertyNames = isNavigationPropertyForward === !step.relationshipReverse ? { this: (0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.targetAlias, "ECInstanceId"), next: (0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(prev.alias, navigationProperty.name, "Id"), } : { this: (0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.targetAlias, navigationProperty.name, "Id"), next: (0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(prev.alias, prev.joinPropertyName), }; clause += ` ${getJoinClause(step.joinType)} ${getClassSelectClause(step.target, step.targetAlias)} ON ${relationshipJoinPropertyNames.this} = ${relationshipJoinPropertyNames.next} `; prev = { alias: step.targetAlias, className: step.target.fullName, joinPropertyName: "ECInstanceId", }; } else { const relationshipJoinPropertyNames = !step.relationshipReverse ? { this: "SourceECInstanceId", next: "TargetECInstanceId" } : { this: "TargetECInstanceId", next: "SourceECInstanceId" }; if (step.joinType === "outer") { clause += ` ${getJoinClause("outer")} ( SELECT [${step.relationshipAlias}].* FROM ${getClassSelectClause(step.relationship, step.relationshipAlias)} ${getJoinClause("inner")} ${getClassSelectClause(step.target, step.targetAlias)} ON ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.targetAlias, "ECInstanceId")} = ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.relationshipAlias, relationshipJoinPropertyNames.next)} ) [${step.relationshipAlias}] ON ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.relationshipAlias, relationshipJoinPropertyNames.this)} = ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(prev.alias, prev.joinPropertyName)} `; } else { clause += ` ${getJoinClause("inner")} ${getClassSelectClause(step.relationship, step.relationshipAlias)} ON ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.relationshipAlias, relationshipJoinPropertyNames.this)} = ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(prev.alias, prev.joinPropertyName)} `; } clause += ` ${getJoinClause(step.joinType)} ${getClassSelectClause(step.target, step.targetAlias)} ON ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.targetAlias, "ECInstanceId")} = ${(0, ECSqlValueSelectorSnippets_js_1.createRawPropertyValueSelector)(step.relationshipAlias, relationshipJoinPropertyNames.next)} `; prev = { alias: step.targetAlias, className: step.target.fullName, joinPropertyName: "ECInstanceId", }; } } return clause; } async function getRelationshipPathStepClasses(schemaProvider, step) { const { sourceClassName, relationshipName, targetClassName, ...rest } = step; return { ...rest, source: await (0, Metadata_js_1.getClass)(schemaProvider, sourceClassName), relationship: (await (0, Metadata_js_1.getClass)(schemaProvider, relationshipName)), target: await (0, Metadata_js_1.getClass)(schemaProvider, targetClassName), }; } async function getNavigationProperty(step) { const source = !step.relationshipReverse ? step.source : step.target; const target = !step.relationshipReverse ? step.target : step.source; for (const prop of await source.getProperties()) { if (prop.isNavigation() && prop.direction === "Forward" && (await prop.relationshipClass).fullName === step.relationship.fullName) { return prop; } } for (const prop of await target.getProperties()) { if (prop.isNavigation() && prop.direction === "Backward" && (await prop.relationshipClass).fullName === step.relationship.fullName) { return prop; } } return undefined; } function getJoinClause(type) { if (type === "outer") { return "OUTER JOIN"; } return "INNER JOIN"; } function getClassSelectClause(ecClass, alias) { const classSelector = `[${ecClass.schema.name}].[${ecClass.name}]`; return `${classSelector} [${alias}]`; } //# sourceMappingURL=ECSqlJoinSnippets.js.map