2022-01-27 01:37:54 +00:00
|
|
|
import {CanonicalItemClass} from '../../CanonicalReceiver'
|
|
|
|
import {BaseSerializer} from './BaseSerializer'
|
|
|
|
import {Awaitable, ErrorWithContext, JSONState, Rehydratable} from '../../../util'
|
|
|
|
import {Container, Inject, Injectable} from '../../../di'
|
|
|
|
import {Canon} from '../../../service/Canon'
|
2022-01-27 16:34:01 +00:00
|
|
|
import {ObjectSerializer} from './decorators'
|
2022-01-27 01:37:54 +00:00
|
|
|
|
|
|
|
/** State encoded by this class. */
|
|
|
|
export interface SimpleCanonicalItemSerialState extends JSONState {
|
|
|
|
rehydrate?: JSONState
|
|
|
|
canonicalIdentifier: string
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A serializer implementation that serializes class instances derived from the Canon loading system.
|
|
|
|
* These instances must be CanonicalItemClass instances and take no constructor parameters.
|
|
|
|
* If the instance is Rehydratable, then the state will be (re-)stored.
|
|
|
|
*/
|
2022-01-27 16:34:01 +00:00
|
|
|
@ObjectSerializer()
|
2022-01-27 01:37:54 +00:00
|
|
|
@Injectable()
|
|
|
|
export class SimpleCanonicalItemSerializer<TActual extends CanonicalItemClass> extends BaseSerializer<TActual, SimpleCanonicalItemSerialState> {
|
|
|
|
@Inject()
|
|
|
|
protected readonly canon!: Canon
|
|
|
|
|
|
|
|
@Inject()
|
|
|
|
protected readonly container!: Container
|
|
|
|
|
|
|
|
protected decodeSerial(serial: SimpleCanonicalItemSerialState): Awaitable<TActual> {
|
|
|
|
const canon = this.canon.getFromFullyQualified(serial.canonicalIdentifier)
|
|
|
|
if ( !canon ) {
|
|
|
|
throw new ErrorWithContext('Unable to decode serialized payload: the canonical identifier was not found', {
|
|
|
|
serial,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( canon instanceof CanonicalItemClass ) {
|
|
|
|
if ( serial.rehydrate && typeof (canon as any).rehydrate === 'function' ) {
|
|
|
|
(canon as unknown as Rehydratable).rehydrate(serial.rehydrate)
|
|
|
|
}
|
|
|
|
|
|
|
|
return canon as TActual
|
|
|
|
} else if ( canon?.prototype instanceof CanonicalItemClass ) {
|
|
|
|
const inst = this.container.make(canon)
|
|
|
|
if ( serial.rehydrate && typeof (inst as any).rehydrate === 'function' ) {
|
|
|
|
(inst as unknown as Rehydratable).rehydrate(serial.rehydrate)
|
|
|
|
}
|
|
|
|
|
|
|
|
return inst as TActual
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ErrorWithContext('Attempted to instantiate serialized item into non-Canonical class', {
|
|
|
|
canon,
|
|
|
|
serial,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
protected async encodeActual(actual: TActual): Promise<SimpleCanonicalItemSerialState> {
|
|
|
|
const ctor = actual.constructor as typeof CanonicalItemClass
|
|
|
|
const canonicalIdentifier = ctor.getFullyQualifiedCanonicalResolver()
|
|
|
|
if ( !canonicalIdentifier ) {
|
|
|
|
throw new ErrorWithContext('Unable to determine Canonical resolver for serialization.', [
|
|
|
|
actual,
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
const state: SimpleCanonicalItemSerialState = {
|
|
|
|
canonicalIdentifier,
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( typeof (actual as any).dehydrate === 'function' ) {
|
|
|
|
state.rehydrate = await (actual as unknown as Rehydratable).dehydrate()
|
|
|
|
}
|
|
|
|
|
|
|
|
return state
|
|
|
|
}
|
|
|
|
|
|
|
|
protected getName(): string {
|
|
|
|
return '@extollo/lib:SimpleCanonicalItemSerializer'
|
|
|
|
}
|
|
|
|
|
|
|
|
matchActual(some: TActual): boolean {
|
|
|
|
return (
|
|
|
|
some instanceof CanonicalItemClass
|
|
|
|
&& some.constructor.length === 0
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|