import { Exclude } from 'class-transformer' import { JsonTransformer } from '../utils/JsonTransformer' import { DateTransformer, MetadataTransformer } from '../utils/transformers' import { Metadata } from './Metadata' export type TagValue = string | boolean | undefined | Array | null export type TagsBase = { [key: string]: TagValue [key: number]: never } export type Tags = CustomTags & DefaultTags export type RecordTags = ReturnType // The BaseRecord requires a DefaultTags and CustomTags type, but we want to be // able to use the BaseRecord without specifying these types. If we don't specify // these types, the default TagsBase will be used, but this is not compatible // with records that have specified a custom type. // eslint-disable-next-line @typescript-eslint/no-explicit-any export type BaseRecordAny = BaseRecord export abstract class BaseRecord< DefaultTags extends TagsBase = TagsBase, CustomTags extends TagsBase = TagsBase, // We want an empty object, as Record will make typescript // not infer the types correctly // eslint-disable-next-line @typescript-eslint/ban-types MetadataValues = {} > { protected _tags: CustomTags = {} as CustomTags public id!: string @DateTransformer() public createdAt!: Date @DateTransformer() public updatedAt?: Date @Exclude() public readonly type = BaseRecord.type public static readonly type: string = 'BaseRecord' /** @inheritdoc {Metadata#Metadata} */ @MetadataTransformer() public metadata: Metadata = new Metadata({}) /** * Get all tags. This is includes custom and default tags * @returns tags object */ public abstract getTags(): Tags /** * Set the value for a tag * @param name name of the tag * @param value value of the tag */ public setTag(name: keyof CustomTags, value: CustomTags[keyof CustomTags]) { this._tags[name] = value } /** * Get the value for a tag * @param name name of the tag * @returns The tag value, or undefined if not found */ public getTag(name: keyof CustomTags | keyof DefaultTags) { return this.getTags()[name] } /** * Set custom tags. This will merge the tags object with passed in tag properties * * @param tags the tags to set */ public setTags(tags: Partial) { this._tags = { ...this._tags, ...tags, } } /** * Replace tags. This will replace the whole tags object. * Default tags will still be overridden when retrieving tags * * @param tags the tags to set */ public replaceTags(tags: CustomTags & Partial) { this._tags = tags } public toJSON(): Record { return JsonTransformer.toJSON(this) } /** * Clones the record. */ public clone() { return JsonTransformer.clone(this) } }