import {BaseSerializer, ObjectSerializer} from '../../support/bus' import {Model} from './Model' import {Awaitable, ErrorWithContext, JSONState, Maybe} from '../../util' import {QueryRow} from '../types' import {Inject, Injectable, isInstantiable} from '../../di' import {Canon} from '../../service/Canon' export interface ModelSerialPayload extends JSONState { canonicalResolver: string, primaryKey: any, objectValues: QueryRow, } @ObjectSerializer() @Injectable() export class ModelSerializer extends BaseSerializer, ModelSerialPayload> { @Inject() protected readonly canon!: Canon protected async decodeSerial(serial: ModelSerialPayload): Promise> { const ModelClass = this.canon.getFromFullyQualified(serial.canonicalResolver) as typeof Model if ( !ModelClass || !(ModelClass.prototype instanceof Model) || !isInstantiable>(ModelClass) ) { throw new ErrorWithContext('Cannot decode serialized model as canonical resolver is invalid', { serial, }) } let inst: Maybe> = this.make>(ModelClass) if ( serial.primaryKey ) { inst = await ModelClass.query() .whereKey(serial.primaryKey) .first() } if ( !inst ) { throw new ErrorWithContext('Could not look up serialized model', { serial, }) } await inst.assume(serial.objectValues) return inst } protected encodeActual(actual: Model): Awaitable { const ctor = actual.constructor as typeof Model const canonicalResolver = ctor.getFullyQualifiedCanonicalResolver() if ( !canonicalResolver ) { throw new ErrorWithContext('Unable to serialize model: no Canonical resolver', { actual, }) } return { canonicalResolver, primaryKey: actual.key(), objectValues: actual.toObject(), } } protected getName(): string { return '@extollo/lib.ModelSerializer' } matchActual(some: Model): boolean { return some instanceof Model } }