diff --git a/cli/api/commands/build.ts b/cli/api/commands/build.ts index 74305b06a..d8e651227 100644 --- a/cli/api/commands/build.ts +++ b/cli/api/commands/build.ts @@ -2,7 +2,6 @@ import { prune } from "df/cli/api/commands/prune"; import { state } from "df/cli/api/commands/state"; import * as dbadapters from "df/cli/api/dbadapters"; import { ExecutionSql } from "df/cli/api/dbadapters/execution_sql"; -import { StringifiedMap, StringifiedSet } from "df/common/strings/stringifier"; import { targetStringifier } from "df/core/targets"; import * as utils from "df/core/utils"; import { dataform } from "df/protos/ts"; @@ -14,15 +13,17 @@ export async function build( ) { const prunedGraph = prune(compiledGraph, runConfig); - const allInvolvedTargets = new StringifiedSet( - targetStringifier, - prunedGraph.tables.map(table => table.target) + const allInvolvedTargets = new Set( + prunedGraph.tables.map(table => targetStringifier.stringify(table.target)) ); return new Builder( prunedGraph, runConfig, - await state(dbadapter, Array.from(allInvolvedTargets)) + await state( + dbadapter, + Array.from(allInvolvedTargets).map(target => targetStringifier.parse(target)) + ) ).build(); } @@ -46,16 +47,19 @@ export class Builder { throw new Error(`Project has unresolved compilation or validation errors.`); } - const tableMetadataByTarget = new StringifiedMap( - targetStringifier - ); + const tableMetadataByTarget = new Map(); + this.warehouseState.tables.forEach(tableState => { - tableMetadataByTarget.set(tableState.target, tableState); + tableMetadataByTarget.set(targetStringifier.stringify(tableState.target), tableState); }); const actions: dataform.IExecutionAction[] = [].concat( this.prunedGraph.tables.map(t => - this.buildTable(t, tableMetadataByTarget.get(t.target), this.runConfig) + this.buildTable( + t, + tableMetadataByTarget.get(targetStringifier.stringify(t.target)), + this.runConfig + ) ), this.prunedGraph.operations.map(o => this.buildOperation(o)), this.prunedGraph.assertions.map(a => this.buildAssertion(a)) diff --git a/cli/api/commands/run.ts b/cli/api/commands/run.ts index b40e06326..2a753c08d 100644 --- a/cli/api/commands/run.ts +++ b/cli/api/commands/run.ts @@ -6,7 +6,6 @@ import { IBigQueryExecutionOptions } from "df/cli/api/dbadapters/bigquery"; import { Flags } from "df/common/flags"; import { retry } from "df/common/promises"; import { deepClone, equals } from "df/common/protos"; -import { StringifiedMap, StringifiedSet } from "df/common/strings/stringifier"; import { targetStringifier } from "df/core/targets"; import { dataform } from "df/protos/ts"; @@ -45,17 +44,14 @@ export function run( } export class Runner { - private readonly warehouseStateByTarget: StringifiedMap< - dataform.ITarget, - dataform.ITableMetadata - >; + private readonly warehouseStateByTarget: Map; - private readonly allActionTargets: StringifiedSet; + private readonly allActionTargets: Set; private readonly runResult: dataform.IRunResult; private readonly changeListeners: Array<(graph: dataform.IRunResult) => void> = []; private readonly eEmitter: EventEmitter; - private executedActionTargets: StringifiedSet; - private successfullyExecutedActionTargets: StringifiedSet; + private executedActionTargets: Set; + private successfullyExecutedActionTargets: Set; private pendingActions: dataform.IExecutionAction[]; private lastNotificationTimestampMillis = 0; private stopped = false; @@ -71,30 +67,32 @@ export class Runner { partiallyExecutedRunResult: dataform.IRunResult = {}, private readonly runnerNotificationPeriodMillis: number = flags.runnerNotificationPeriodMillis.get() ) { - this.allActionTargets = new StringifiedSet( - targetStringifier, - graph.actions.map(action => action.target) + this.allActionTargets = new Set( + graph.actions.map(action => targetStringifier.stringify(action.target)) ); this.runResult = { actions: [], ...partiallyExecutedRunResult }; - this.warehouseStateByTarget = new StringifiedMap( - targetStringifier, - graph.warehouseState.tables?.map(tableMetadata => [tableMetadata.target, tableMetadata]) + this.warehouseStateByTarget = new Map(); + graph.warehouseState.tables?.forEach(tableMetadata => + this.warehouseStateByTarget.set( + targetStringifier.stringify(tableMetadata.target), + tableMetadata + ) ); - this.executedActionTargets = new StringifiedSet( - targetStringifier, + this.executedActionTargets = new Set( this.runResult.actions .filter(action => action.status !== dataform.ActionResult.ExecutionStatus.RUNNING) - .map(action => action.target) + .map(action => targetStringifier.stringify(action.target)) ); - this.successfullyExecutedActionTargets = new StringifiedSet( - targetStringifier, - this.runResult.actions.filter(isSuccessfulAction).map(action => action.target) + this.successfullyExecutedActionTargets = new Set( + this.runResult.actions + .filter(isSuccessfulAction) + .map(action => targetStringifier.stringify(action.target)) ); this.pendingActions = graph.actions.filter( - action => !this.executedActionTargets.has(action.target) + action => !this.executedActionTargets.has(targetStringifier.stringify(action.target)) ); this.eEmitter = new EventEmitter(); // There could feasibly be thousands of listeners to this, 0 makes the limit infinite. @@ -247,8 +245,8 @@ export class Runner { // have executed successfully. pendingAction.dependencyTargets.every( dependency => - !this.allActionTargets.has(dependency) || - this.successfullyExecutedActionTargets.has(dependency) + !this.allActionTargets.has(targetStringifier.stringify(dependency)) || + this.successfullyExecutedActionTargets.has(targetStringifier.stringify(dependency)) ) ) { executableActions.push(pendingAction); @@ -257,7 +255,8 @@ export class Runner { // exist in the graph, or have completed execution. pendingAction.dependencyTargets.every( dependency => - !this.allActionTargets.has(dependency) || this.executedActionTargets.has(dependency) + !this.allActionTargets.has(targetStringifier.stringify(dependency)) || + this.executedActionTargets.has(targetStringifier.stringify(dependency)) ) ) { skippableActions.push(pendingAction); @@ -287,9 +286,11 @@ export class Runner { Promise.all( executableActions.map(async executableAction => { const actionResult = await this.executeAction(executableAction); - this.executedActionTargets.add(executableAction.target); + this.executedActionTargets.add(targetStringifier.stringify(executableAction.target)); if (isSuccessfulAction(actionResult)) { - this.successfullyExecutedActionTargets.add(executableAction.target); + this.successfullyExecutedActionTargets.add( + targetStringifier.stringify(executableAction.target) + ); } await this.executeAllActionsReadyForExecution(); }) @@ -383,7 +384,7 @@ export class Runner { } } - this.warehouseStateByTarget.delete(action.target); + this.warehouseStateByTarget.delete(targetStringifier.stringify(action.target)); if (actionResult.status === dataform.ActionResult.ExecutionStatus.RUNNING) { actionResult.status = dataform.ActionResult.ExecutionStatus.SUCCESSFUL; diff --git a/cli/api/utils/graphs.ts b/cli/api/utils/graphs.ts index 81f8c4c9e..30271be3c 100644 --- a/cli/api/utils/graphs.ts +++ b/cli/api/utils/graphs.ts @@ -1,35 +1,39 @@ -import { StringifiedMap } from "df/common/strings/stringifier"; import { targetStringifier } from "df/core/targets"; import { dataform } from "df/protos/ts"; -export const combineAllActions = (graph: dataform.ICompiledGraph) => { - return ([] as Array< - dataform.ITable | dataform.IOperation | dataform.IAssertion | dataform.IDeclaration | dataform.IDataPreparation - >).concat( +type CoreProtoActionTypes = + | dataform.ITable + | dataform.IOperation + | dataform.IAssertion + | dataform.IDeclaration + | dataform.IDataPreparation; + +function combineAllActions(graph: dataform.ICompiledGraph) { + return ([] as CoreProtoActionTypes[]).concat( graph.tables || ([] as dataform.ITable[]), graph.operations || ([] as dataform.IOperation[]), graph.assertions || ([] as dataform.IAssertion[]), graph.declarations || ([] as dataform.IDeclaration[]), graph.dataPreparations || ([] as dataform.IDataPreparation[]) ); -}; +} export function actionsByTarget(compiledGraph: dataform.ICompiledGraph) { - return new StringifiedMap( - targetStringifier, - combineAllActions(compiledGraph) - // Required for backwards compatibility with old versions of @dataform/core. - .filter(action => !!action.target) - .map(action => [action.target, action]) - ); + const actionsMap = new Map(); + combineAllActions(compiledGraph) + // Required for backwards compatibility with old versions of @dataform/core. + .filter(action => !!action.target) + .forEach(action => { + actionsMap.set(targetStringifier.stringify(action.target), action); + }); } export function actionsByCanonicalTarget(compiledGraph: dataform.ICompiledGraph) { - return new StringifiedMap( - targetStringifier, - combineAllActions(compiledGraph) - // Required for backwards compatibility with old versions of @dataform/core. - .filter(action => !!action.canonicalTarget) - .map(action => [action.canonicalTarget, action]) - ); + const actionsMap = new Map(); + combineAllActions(compiledGraph) + // Required for backwards compatibility with old versions of @dataform/core. + .filter(action => !!action.canonicalTarget) + .forEach(action => { + actionsMap.set(targetStringifier.stringify(action.canonicalTarget), action); + }); } diff --git a/cli/console.ts b/cli/console.ts index f465e236b..de892c7bc 100644 --- a/cli/console.ts +++ b/cli/console.ts @@ -404,7 +404,7 @@ function printExecutedActionErrors( executionAction: dataform.IExecutionAction ) { const failingTasks = executedAction.tasks.filter( - task => task.status === dataform.ActionResult.ExecutionStatus.FAILED + task => task.status === dataform.TaskResult.ExecutionStatus.FAILED ); failingTasks.forEach((task, i) => { executionAction.tasks[i].statement.split("\n").forEach(line => { diff --git a/cli/vm/compile.ts b/cli/vm/compile.ts index 2381a60fe..e42a83aaa 100644 --- a/cli/vm/compile.ts +++ b/cli/vm/compile.ts @@ -86,7 +86,7 @@ if (require.main === module) { } /** - * @returns a base64 encoded {@see dataform.CoreExecutionRequest} proto. + * @returns a base64 encoded @see {@link dataform.CoreExecutionRequest} proto. */ function createCoreExecutionRequest(compileConfig: dataform.ICompileConfig): string { const filePaths = Array.from( diff --git a/common/strings/stringifier.spec.ts b/common/strings/stringifier.spec.ts index c03d9b550..3d25abcde 100644 --- a/common/strings/stringifier.spec.ts +++ b/common/strings/stringifier.spec.ts @@ -1,11 +1,7 @@ import { expect } from "chai"; import { basename } from "path"; -import { - JSONObjectStringifier, - StringifiedMap, - StringifiedSet -} from "df/common/strings/stringifier"; +import { JSONObjectStringifier } from "df/common/strings/stringifier"; import { suite, test } from "df/testing"; interface IKey { @@ -50,83 +46,4 @@ suite(basename(__filename), () => { expect(stringifier.stringify(value)).equals(stringifier.stringify(value2)); }); }); - - suite("stringified map", () => { - const jsonStringifiedMap = new StringifiedMap(new JSONObjectStringifier(), [ - [{ a: "1", b: 2 }, "x"], - [{ a: "2", b: 2 }, "y"], - [{ a: "2", b: 3 }, "z"] - ]); - - test("has correct stringified keys", () => { - expect([...jsonStringifiedMap.keys()]).deep.equals([ - { a: "1", b: 2 }, - { a: "2", b: 2 }, - { a: "2", b: 3 } - ]); - }); - - test("has correct stringified iterator", () => { - expect([...jsonStringifiedMap]).deep.equals([ - [{ a: "1", b: 2 }, "x"], - [{ a: "2", b: 2 }, "y"], - [{ a: "2", b: 3 }, "z"] - ]); - }); - - test("set and get", () => { - const map = new StringifiedMap(new JSONObjectStringifier()); - map.set( - { - a: "1", - b: 2 - }, - "test" - ); - expect( - map.get({ - a: "1", - b: 2 - }) - ).equals("test"); - }); - }); - - suite("stringified set", () => { - const jsonStringifiedSet = new StringifiedSet(new JSONObjectStringifier(), [ - { a: "1", b: 2 }, - { a: "2", b: 2 }, - { a: "2", b: 3 } - ]); - - test("has correct stringified values", () => { - expect([...jsonStringifiedSet.values()]).deep.equals([ - { a: "1", b: 2 }, - { a: "2", b: 2 }, - { a: "2", b: 3 } - ]); - }); - - test("has correct stringified iterator", () => { - expect([...jsonStringifiedSet]).deep.equals([ - { a: "1", b: 2 }, - { a: "2", b: 2 }, - { a: "2", b: 3 } - ]); - }); - - test("add and has", () => { - const set = new StringifiedSet(new JSONObjectStringifier()); - set.add({ - a: "1", - b: 2 - }); - expect( - set.has({ - a: "1", - b: 2 - }) - ).equals(true); - }); - }); }); diff --git a/common/strings/stringifier.ts b/common/strings/stringifier.ts index 46e975a43..e28fd3c37 100644 --- a/common/strings/stringifier.ts +++ b/common/strings/stringifier.ts @@ -1,5 +1,3 @@ -import Long from "long"; - export interface IStringifier { stringify: (value: T) => string; parse: (value: string) => T; @@ -21,201 +19,3 @@ export class JSONObjectStringifier implements IStringifier { return JSON.parse(value) as T; } } - -export class StringifiedMap implements Map { - get [Symbol.toStringTag]() { - return StringifiedMap.name; - } - - get size() { - return this.map.size; - } - - private map: Map; - - constructor( - private readonly stringifier: IStringifier, - // tslint:disable-next-line: array-type - entries?: readonly (readonly [K, V])[] | null - ) { - if (entries) { - this.map = new Map( - entries.map(([key, value]) => [stringifier.stringify(key), value]) - ); - } else { - this.map = new Map(); - } - } - - public clear(): void { - return this.map.clear(); - } - - public delete(key: K): boolean { - return this.map.delete(this.stringifier.stringify(key)); - } - - public forEach(callbackfn: (value: V, key: K, map: Map) => void, thisArg?: any): void { - return this.map.forEach( - (value, key, _) => callbackfn(value, this.stringifier.parse(key), null), - thisArg - ); - } - - public get(key: K): V { - return this.map.get(this.stringifier.stringify(key)); - } - - public has(key: K): boolean { - return this.map.has(this.stringifier.stringify(key)); - } - - public set(key: K, value: V): this { - this.map.set(this.stringifier.stringify(key), value); - return this; - } - - public [Symbol.iterator](): IterableIterator<[K, V]> { - return this.entries(); - } - - public entries(): IterableIterator<[K, V]> { - const stringifier = this.stringifier; - const innerIterator = this.map[Symbol.iterator](); - return new (class Iter implements IterableIterator<[K, V]> { - public [Symbol.iterator](): IterableIterator<[K, V]> { - return this; - } - public next(): IteratorResult<[K, V], any> { - const next = innerIterator.next(); - return { - value: !next.done ? [stringifier.parse(next.value[0]), next.value[1]] : undefined, - done: next.done - }; - } - })(); - } - public keys(): IterableIterator { - const stringifier = this.stringifier; - const innerIterator = this.map.keys(); - return new (class Iter implements IterableIterator { - public [Symbol.iterator](): IterableIterator { - return this; - } - public next(): IteratorResult { - const next = innerIterator.next(); - return { - value: !next.done ? stringifier.parse(next.value) : undefined, - done: next.done - }; - } - })(); - } - public values(): IterableIterator { - return this.map.values(); - } -} - -export class StringifiedSet implements Set { - get size() { - return this.set.size; - } - - get [Symbol.toStringTag]() { - return StringifiedSet.name; - } - - private set: Set; - - constructor( - private readonly stringifier: IStringifier, - // tslint:disable-next-line: array-type - values?: readonly T[] | null - ) { - if (values) { - this.set = new Set(values.map(value => stringifier.stringify(value))); - } else { - this.set = new Set(); - } - } - - public add(value: T): this { - this.set.add(this.stringifier.stringify(value)); - return this; - } - - public clear(): void { - return this.set.clear(); - } - - public delete(value: T): boolean { - return this.set.delete(this.stringifier.stringify(value)); - } - - public forEach(callbackfn: (value: T, value2: T, set: Set) => void, thisArg?: any): void { - return this.set.forEach( - (value, value2, _) => - callbackfn(this.stringifier.parse(value), this.stringifier.parse(value2), null), - thisArg - ); - } - - public has(value: T): boolean { - return this.set.has(this.stringifier.stringify(value)); - } - - public [Symbol.iterator](): IterableIterator { - return this.keys(); - } - - public entries(): IterableIterator<[T, T]> { - const stringifier = this.stringifier; - const innerIterator = this.set[Symbol.iterator](); - return new (class Iter implements IterableIterator<[T, T]> { - public [Symbol.iterator](): IterableIterator<[T, T]> { - return this; - } - public next(): IteratorResult<[T, T], any> { - const next = innerIterator.next(); - return { - value: !next.done ? [stringifier.parse(next.value[0]), next.value[1]] : undefined, - done: next.done - }; - } - })(); - } - - public keys(): IterableIterator { - const stringifier = this.stringifier; - const innerIterator = this.set.keys(); - return new (class Iter implements IterableIterator { - public [Symbol.iterator](): IterableIterator { - return this; - } - public next(): IteratorResult { - const next = innerIterator.next(); - return { - value: !next.done ? stringifier.parse(next.value) : undefined, - done: next.done - }; - } - })(); - } - - public values(): IterableIterator { - const stringifier = this.stringifier; - const innerIterator = this.set.values(); - return new (class Iter implements IterableIterator { - public [Symbol.iterator](): IterableIterator { - return this; - } - public next(): IteratorResult { - const next = innerIterator.next(); - return { - value: !next.done ? stringifier.parse(next.value) : undefined, - done: next.done - }; - } - })(); - } -} diff --git a/core/actions/test.ts b/core/actions/test.ts index cd265812c..16e812222 100644 --- a/core/actions/test.ts +++ b/core/actions/test.ts @@ -1,5 +1,4 @@ import { verifyObjectMatchesProto, VerifyProtoErrorBehaviour } from "df/common/protos"; -import { StringifiedMap } from "df/common/strings/stringifier"; import { ActionBuilder, ITableContext, TableType } from "df/core/actions"; import { Table } from "df/core/actions/table"; import { View } from "df/core/actions/view"; @@ -36,10 +35,7 @@ export class Test extends ActionBuilder { public proto: dataform.ITest = dataform.Test.create(); public session: Session; - public contextableInputs = new StringifiedMap< - dataform.ITarget, - Contextable - >(targetStringifier); + public contextableInputs = new Map>(); private datasetToTest: Resolvable; private contextableQuery: Contextable; @@ -67,7 +63,10 @@ export class Test extends ActionBuilder { } public input(refName: string | string[], contextableQuery: Contextable) { - this.contextableInputs.set(resolvableAsTarget(toResolvable(refName)), contextableQuery); + this.contextableInputs.set( + targetStringifier.stringify(resolvableAsTarget(toResolvable(refName))), + contextableQuery + ); return this; } @@ -166,7 +165,7 @@ class RefReplacingContext implements ITableContext { public resolve(ref: Resolvable | string[], ...rest: string[]) { const target = resolvableAsTarget(toResolvable(ref, rest)); - if (!this.testContext.test.contextableInputs.has(target)) { + if (!this.testContext.test.contextableInputs.has(targetStringifier.stringify(target))) { this.testContext.test.session.compileError( new Error( `Input for dataset "${JSON.stringify( @@ -178,7 +177,9 @@ class RefReplacingContext implements ITableContext { ); return ""; } - return `(${this.testContext.apply(this.testContext.test.contextableInputs.get(target))})`; + return `(${this.testContext.apply( + this.testContext.test.contextableInputs.get(targetStringifier.stringify(target)) + )})`; } public apply(value: Contextable): T { diff --git a/core/main.ts b/core/main.ts index 461d12d6c..348929e42 100644 --- a/core/main.ts +++ b/core/main.ts @@ -21,8 +21,8 @@ import { dataform } from "df/protos/ts"; /** * This is the main entry point into the user space code that should be invoked by the compilation wrapper sandbox. * - * @param coreExecutionRequest an encoded {@see dataform.CoreExecutionRequest} proto. - * @returns an encoded {@see dataform.CoreExecutionResponse} proto. + * @param coreExecutionRequest an encoded @see {@link dataform.CoreExecutionRequest} proto. + * @returns an encoded @see {@link dataform.CoreExecutionResponse} proto. */ export function main(coreExecutionRequest: Uint8Array | string): Uint8Array | string { const globalAny = global as any; diff --git a/core/session.ts b/core/session.ts index f3d7964be..e4102d226 100644 --- a/core/session.ts +++ b/core/session.ts @@ -1,7 +1,6 @@ import { default as TarjanGraphConstructor, Graph as TarjanGraph } from "tarjan-graph"; import { encode64, verifyObjectMatchesProto, VerifyProtoErrorBehaviour } from "df/common/protos"; -import { StringifiedMap, StringifiedSet } from "df/common/strings/stringifier"; import { Action, ILegacyTableConfig, ITableContext, TableType } from "df/core/actions"; import { AContextable, Assertion, AssertionContext } from "df/core/actions/assertion"; import { @@ -556,15 +555,16 @@ export class Session { return; } - const newTargetByOriginalTarget = new StringifiedMap( - targetStringifier - ); + const newTargetByOriginalTarget = new Map(); declarationTargets.forEach(declarationTarget => - newTargetByOriginalTarget.set(declarationTarget, declarationTarget) + newTargetByOriginalTarget.set( + targetStringifier.stringify(declarationTarget), + declarationTarget + ) ); actions.forEach(action => { - newTargetByOriginalTarget.set(action.target, { + newTargetByOriginalTarget.set(targetStringifier.stringify(action.target), { ...action.target, database: action.target.database && @@ -572,17 +572,17 @@ export class Session { schema: `${action.target.schema}${this.getSchemaSuffixWithUnderscore()}`, name: `${this.getTablePrefixWithUnderscore()}${action.target.name}` }); - action.target = newTargetByOriginalTarget.get(action.target); + action.target = newTargetByOriginalTarget.get(targetStringifier.stringify(action.target)); }); // Fix up dependencies in case those dependencies' names have changed. const getUpdatedTarget = (originalTarget: dataform.ITarget) => { // It's possible that we don't have a new Target for a dependency that failed to compile, // so fall back to the original Target. - if (!newTargetByOriginalTarget.has(originalTarget)) { + if (!newTargetByOriginalTarget.has(targetStringifier.stringify(originalTarget))) { return originalTarget; } - return newTargetByOriginalTarget.get(originalTarget); + return newTargetByOriginalTarget.get(targetStringifier.stringify(originalTarget)); }; actions.forEach(action => { action.dependencyTargets = (action.dependencyTargets || []).map(getUpdatedTarget); @@ -719,15 +719,15 @@ export class Session { } private removeNonUniqueActionsFromCompiledGraph(compiledGraph: dataform.CompiledGraph) { - function getNonUniqueTargets(targets: dataform.ITarget[]): StringifiedSet { - const allTargets = new StringifiedSet(targetStringifier); - const nonUniqueTargets = new StringifiedSet(targetStringifier); + function getNonUniqueTargets(targets: dataform.ITarget[]): Set { + const allTargets = new Set(); + const nonUniqueTargets = new Set(); targets.forEach(target => { - if (allTargets.has(target)) { - nonUniqueTargets.add(target); + if (allTargets.has(targetStringifier.stringify(target))) { + nonUniqueTargets.add(targetStringifier.stringify(target)); } - allTargets.add(target); + allTargets.add(targetStringifier.stringify(target)); }); return nonUniqueTargets; @@ -748,9 +748,11 @@ export class Session { ); const isUniqueAction = (action: IActionProto) => { - const isNonUniqueTarget = nonUniqueActionsTargets.has(action.target); + const isNonUniqueTarget = nonUniqueActionsTargets.has( + targetStringifier.stringify(action.target) + ); const isNonUniqueCanonicalTarget = nonUniqueActionsCanonicalTargets.has( - action.canonicalTarget + targetStringifier.stringify(action.canonicalTarget) ); if (isNonUniqueTarget) { diff --git a/core/targets.ts b/core/targets.ts index 99492b91f..5ec746c25 100644 --- a/core/targets.ts +++ b/core/targets.ts @@ -10,7 +10,7 @@ export const targetStringifier = new JSONObjectStringifier(); * This is effectively equivelant to an action "name". * * This is an ambiguous transformation, multiple targets may map to the same string - * and it should not be used for indexing. Use {@code targetStringifier} instead. + * and it should not be used for indexing. Use @see {@link targetStringifier} instead. * * TODO(ekrekr): replace remaining incorrect usage of this with targetStringifier. */