From a544a2868e164369e4bb6cdd7fc1d6ed3b9ca83b Mon Sep 17 00:00:00 2001 From: bangbang93 Date: Wed, 7 Jun 2023 19:43:01 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8ReflectMetadata?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.ts | 10 +++++----- src/meta.ts | 24 +++++++++++++----------- src/schema.ts | 46 ++++++++++++++++++++-------------------------- 3 files changed, 38 insertions(+), 42 deletions(-) diff --git a/src/index.ts b/src/index.ts index 664c18e..2f3b6cd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,7 @@ import {Document, HydratedDocument, model, Model, Schema, Types} from 'mongoose' import 'reflect-metadata' import {Class, Constructor} from 'type-fest' -import {Fn, getMongooseMeta, IMongooseClass, MongooseMeta} from './meta' +import {Fn, getMongooseMeta, MongooseMeta} from './meta' import {ActionType, HookType} from './middleware' export * from './model' @@ -32,7 +32,7 @@ export type RichModelType, THelper = object> = Mod export type Ref = T['_id'] | T export type RefDocument = T['_id'] | DocumentType -const modelCache = new WeakMap, RichModelType>() +const modelCache = new WeakMap, Model>() const schemaCache = new WeakMap() export function getSchema(modelClass: Class): Schema { @@ -51,9 +51,9 @@ export function getModel>(modelClass: T): RichMode } const meta = getMongooseMeta(modelClass.prototype) if (!meta.name) throw new Error(`name not set for model ${modelClass.constructor.name}`) - const newModel = model(meta.name, getSchema(modelClass)) as unknown as RichModelType - modelCache.set(modelClass, newModel as unknown as RichModelType) - return newModel + const newModel = model(meta.name, getSchema(modelClass)) + modelCache.set(modelClass, newModel) + return newModel as unknown as RichModelType } export function getModelName>(modelClass: T): string { diff --git a/src/meta.ts b/src/meta.ts index 89e3177..252722e 100644 --- a/src/meta.ts +++ b/src/meta.ts @@ -1,5 +1,5 @@ -import {get, set} from 'lodash' import {IndexDirection, IndexOptions, Schema, SchemaOptions, SchemaTypeOptions} from 'mongoose' +import {Constructor} from 'type-fest' import {ActionType, HookType} from './middleware' export type Fn = () => unknown @@ -30,19 +30,21 @@ export class MongooseMeta { public options?: SchemaOptions = undefined } -export const mongooseMeta = Symbol('MongooseMeta') +const mongooseMeta = Symbol('MongooseMeta') -export interface IMongooseClass extends Object { - [mongooseMeta]?: MongooseMeta - - // eslint-disable-next-line @typescript-eslint/no-misused-new - new(...args: unknown[]): IMongooseClass +export function setMongooseMeta(target: object, meta: Partial): void { + const exists = Reflect.getMetadata(mongooseMeta, target) ?? new MongooseMeta() + Reflect.defineMetadata(mongooseMeta, {...exists, ...meta}, target) } export function getMongooseMeta(target: object): MongooseMeta { - if (!get(target, mongooseMeta)) { - set(target, mongooseMeta, new MongooseMeta()) - } + const metadata = Reflect.getMetadata(mongooseMeta, target) + if (metadata) return metadata + const meta = new MongooseMeta() + Reflect.defineMetadata(mongooseMeta, meta, target) + return meta +} - return get(target, mongooseMeta) +export function hasMongooseMeta(target: object): target is Constructor { + return Reflect.hasMetadata(mongooseMeta, target) } diff --git a/src/schema.ts b/src/schema.ts index 33be108..84197f2 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,8 +1,8 @@ import lodash from 'lodash' -import {DefaultType, Schema, SchemaTypeOptions, Types} from 'mongoose' +import {DefaultType, SchemaTypeOptions} from 'mongoose' import {Constructor} from 'type-fest' import {getSchema, validators} from './index' -import {getMongooseMeta, IMongooseClass, mongooseMeta} from './meta' +import {getMongooseMeta, hasMongooseMeta} from './meta' import {getType} from './util' export function prop(options: SchemaTypeOptions = {}, @@ -17,29 +17,21 @@ export function prop(options: SchemaTypeOptions = {}, type = getType(target, name) as object } if (typeof type === 'object' && type !== null && 'prototype' in type) { - if ((type.prototype as any)?.[mongooseMeta] && !pathSchema['type']) { - type = getSchema(type as IMongooseClass) + if (hasMongooseMeta(type) && !pathSchema['type']) { + type = getSchema(type) } } getMongooseMeta(target).schema[name] = {...pathSchema, ...options, ...type ? {type} : {}} as any } } -export function array(type: T, options?: SchemaTypeOptions) { +export function array>(type: T, options?: SchemaTypeOptions) { return (target: object, name: string): void => { let t if (typeof type === 'object' && type !== null) { - if ((lodash.get(type, 'prototype') as any)?.[mongooseMeta]) { - t = getSchema(type as unknown as IMongooseClass) + if (hasMongooseMeta(type)) { + t = getSchema(type) } - if ((lodash.get(type, 'type.prototype') as any)?.[mongooseMeta]) { - lodash.set(type, 'type', getSchema(lodash.get(type, 'type') as IMongooseClass)) - } - } - const path = getMongooseMeta(target).schema[name] - if (!type) type = path['type'] as T - if (type === Types.ObjectId) { - t = Schema.Types.ObjectId } t = t ?? type getMongooseMeta(target).schema[name] @@ -81,11 +73,13 @@ export function defaults>(value: T) { } } -export function type(type: unknown) { +export function type(type: Constructor) { return (target: object, name: string) => { if (typeof type === 'object' && type !== null) { - if (lodash.get(type, 'prototype')?.[mongooseMeta]) { - type = getSchema(type as IMongooseClass) + if (hasMongooseMeta(type)) { + const schema = getSchema(type) + getMongooseMeta(target).schema[name] = {...getMongooseMeta(target).schema[name], type: schema} + return } } getMongooseMeta(target).schema[name] = {...getMongooseMeta(target).schema[name], type} @@ -105,8 +99,8 @@ export function enums(values: Array | Record Constructor export function ref(nameOrClass: string | LazyClass, idType: unknown): (target: object, name: string) => void -export function ref(nameOrClass: IMongooseClass, idType?: unknown): (target: object, name: string) => void -export function ref(nameOrClass: string | IMongooseClass | LazyClass, +export function ref(nameOrClass: Constructor, idType?: unknown): (target: object, name: string) => void +export function ref(nameOrClass: string | Constructor | LazyClass, idType?: unknown): (target: object, name: string) => void { if (typeof nameOrClass === 'string') { return (target: object, name: string) => { @@ -157,7 +151,7 @@ export function ref(nameOrClass: string | IMongooseClass | LazyClass, } } -export function refArray(nameOrClass: string | LazyClass | IMongooseClass, elementType: unknown) { +export function refArray(nameOrClass: string | LazyClass | Constructor, elementType: unknown) { if (typeof nameOrClass === 'string') { return (target: object, name: string) => { getMongooseMeta(target).schema[name] = { @@ -194,19 +188,19 @@ export function refArray(nameOrClass: string | LazyClass | IMongooseClass, eleme } export function statics() { - return (target: Constructor, name: string, descriptor: PropertyDescriptor) => { - getMongooseMeta(target.prototype).statics[name] = descriptor.value + return (target: object, name: string, descriptor: PropertyDescriptor) => { + getMongooseMeta(target).statics[name] = descriptor.value } } export function query() { - return (target: Constructor, name: string, descriptor: PropertyDescriptor) => { - getMongooseMeta(target.prototype).queries[name] = descriptor.value + return (target: object, name: string, descriptor: PropertyDescriptor) => { + getMongooseMeta(target).queries[name] = descriptor.value } } export function methods() { - return (target: Constructor, name: string, descriptor: PropertyDescriptor) => { + return (target: object, name: string, descriptor: PropertyDescriptor) => { getMongooseMeta(target).methods[name] = descriptor.value } }