Skip to content

Commit

Permalink
Added API for querying provenance info for derived transformer classes (
Browse files Browse the repository at this point in the history
#126)

Added methods that allow derived transformer classes to query
synchronization version and provenance Scope aspect.

- Federation guid branch is not backwards compatible when it comes to
supporting old branches. Exposing api to access scope aspect is
necessary so that derived classes can fake the synchronization version
themselves.
- Exporting TargetScopeProvenanceJsonProps for derived classes to make
sense of 'Scope' aspect's jsonProps.
- explicitly calling `initialize` will throw errors if scope provenance
is not initialized in change processing workflow. Exposed
`initScopeProvenance` to derived classes.
  • Loading branch information
ViliusRuskys authored Nov 17, 2023
1 parent 5dabfb8 commit 030da11
Showing 1 changed file with 55 additions and 4 deletions.
59 changes: 55 additions & 4 deletions packages/transformer/src/IModelTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,12 @@ class PartiallyCommittedEntity {
}
}

interface TargetScopeProvenanceJsonProps {
/**
* Data type for persisting change version information within provenance Scope ExternalSourceAspect.
* Additionally, forward synchronization version is stored in Scope aspect's 'version' field.
* @beta
*/
export interface TargetScopeProvenanceJsonProps {
pendingReverseSyncChangesetIndices: number[];
pendingSyncChangesetIndices: number[];
reverseSyncVersion: string;
Expand Down Expand Up @@ -587,8 +592,9 @@ export class IModelTransformer extends IModelExportHandler {

/** the changeset in the scoping element's source version found for this transformation
* @note: the version depends on whether this is a reverse synchronization or not, as
* it is stored separately for both synchronization directions
* @note: empty string and -1 for changeset and index if it has never been transformed
* it is stored separately for both synchronization directions.
* @note: must call [[initScopeProvenance]] before using this property.
* @note: empty string and -1 for changeset and index if it has never been transformed or was transformed before federation guid update (pre 1.x).
*/
private get _synchronizationVersion(): ChangesetIndexAndId {
if (!this._cachedSynchronizationVersion) {
Expand All @@ -608,13 +614,58 @@ export class IModelTransformer extends IModelExportHandler {
return this._cachedSynchronizationVersion;
}

/** the changeset in the scoping element's source version found for this transformation
* @note: the version depends on whether this is a reverse synchronization or not, as
* it is stored separately for both synchronization directions.
* @note: empty string and -1 for changeset and index if it has never been transformed, or was transformed before federation guid update (pre 1.x).
*/
protected get synchronizationVersion(): ChangesetIndexAndId {
if (this._cachedSynchronizationVersion === undefined) {
const provenanceScopeAspect = this.tryGetProvenanceScopeAspect();
if (!provenanceScopeAspect) {
return { index: -1, id: "" }; // first synchronization.
}

const version = this._options.isReverseSynchronization
? (JSON.parse(provenanceScopeAspect.jsonProperties ?? "{}") as TargetScopeProvenanceJsonProps).reverseSyncVersion
: provenanceScopeAspect.version;
if (!version) {
return { index: -1, id: "" }; // previous synchronization was done before fed guid update.
}

const [id, index] = version.split(";");
if (Number.isNaN(Number(index)))
throw new Error("Could not parse version data from scope aspect");
this._cachedSynchronizationVersion = { index: Number(index), id }; // synchronization version found and cached.
}
return this._cachedSynchronizationVersion;
}

/**
* @returns provenance scope aspect if it exists in the provenanceDb.
* Provenance scope aspect is created and inserted into provenanceDb when [[initScopeProvenance]] is invoked.
*/
protected tryGetProvenanceScopeAspect(): ExternalSourceAspect | undefined {
const scopeProvenanceAspectId = this.queryScopeExternalSource({
classFullName: ExternalSourceAspect.classFullName,
scope: { id: IModel.rootSubjectId },
kind: ExternalSourceAspect.Kind.Scope,
element: { id: this.targetScopeElementId ?? IModel.rootSubjectId },
identifier: this.provenanceSourceDb.iModelId,
});

return scopeProvenanceAspectId.aspectId
? this.provenanceDb.elements.getAspect(scopeProvenanceAspectId.aspectId) as ExternalSourceAspect
: undefined;
}

/**
* Make sure there are no conflicting other scope-type external source aspects on the *target scope element*,
* If there are none at all, insert one, then this must be a first synchronization.
* @returns the last synced version (changesetId) on the target scope's external source aspect,
* if this was a [BriefcaseDb]($backend)
*/
private initScopeProvenance(): void {
protected initScopeProvenance(): void {
const aspectProps = {
id: undefined as string | undefined,
version: undefined as string | undefined,
Expand Down

0 comments on commit 030da11

Please sign in to comment.