import { BaseEntity } from "./BaseEntity" ; import { Entity , getMetadata } from "./EntityManager" ; const tagDelimiter = ":" ; type HasTagName = { tagName : string ; idType : "int" | "uuid" ; } ; export function maybeResolveReferenceToId ( value ) { return typeof value === "number" || typeof value === "string" ? value : value ?. id ; } /** Converts `value` to a number, i.e. for string ids, unless its undefined. */ export function keyToNumber ( meta , value ) ; export function keyToNumber ( meta , value ) ; export function keyToNumber ( meta , value ) { if ( value === undefined || value === null ) { return undefined ; } else if ( typeof value === "number" ) { return value ; } else if ( typeof value === "string" ) { const [ tag , id ] = value . split ( tagDelimiter ) ; if ( id === undefined ) { return maybeNumberUnlessUuid ( meta , value ) ; } if ( tag !== meta . tagName ) { throw new Error ( `Invalid tagged id, expected tag ${ meta . tagName }, got ${ value }` ) ; } return maybeNumberUnlessUuid ( meta , id ) ; } else { throw new Error ( `Invalid key ${ value }` ) ; } } function maybeNumberUnlessUuid ( meta , key ) { if ( meta . idType === "uuid" ) { return key as any ; } return Number ( key ) ; } /** Converts `value` to a tagged string, i.e. for string ids, unless its undefined. */ export function keyToString ( meta , value ) { return value === undefined || value === null ? undefined : `${ meta . tagName }:${ value }` ; } /** Fails if any keys are tagged; used by internal functions b/c we still allow most direct API input to be untagged. */ export function assertIdsAreTagged ( keys ) { const invalidKeys = keys . filter ( ( k ) => k . indexOf ( tagDelimiter ) === - 1 ) ; if ( invalidKeys . length > 0 ) { throw new Error ( `Some keys are missing tags ${ invalidKeys }` ) ; } } /** Tags a potentially untagged id, while our API inputs still accept either tagged or untagged ids. */ export function tagIfNeeded ( meta , id ) { if ( id . includes ( tagDelimiter ) ) { return id ; } return `${ meta . tagName }${ tagDelimiter }${ id }` ; } /** Removes the tag prefixes so we can use the keys for SQL operations. */ export function deTagIds ( meta , keys ) { return keys . map ( ( k ) => deTagId ( meta , k ) ) ; } /** Adds the tag prefixes. */ export function tagIds ( meta , keys ) { return keys . map ( ( k ) => tagIfNeeded ( meta , String ( k ) ) ) ; } export function deTagId ( meta , id ) ; export function deTagId ( entity ) ; export function deTagId ( entityOrMeta , id ? ) { const meta = entityOrMeta instanceof BaseEntity ? getMetadata ( entityOrMeta ) : ( entityOrMeta as HasTagName ) ; id = id ?? ( entityOrMeta as Entity ) . id ; return keyToNumber ( meta , id ! ) . toString ( ) ; } /** Removes the tag prefixes so we can use the keys for SQL operations. */ export function unsafeDeTagIds ( keys ) { return keys . map ( ( k ) => k . split ( tagDelimiter ) ) . map ( ( t ) => ( t . length === 0 ? t [ 0 ] : t [ 1 ] ) ) ; } export function tagFromId ( key ) { const parts = key . split ( tagDelimiter ) ; if ( parts . length !== 2 ) { fail ( `Unknown tagged id format: "${ key }"` ) ; } return parts [ 0 ] ; }