Skip to content

Commit

Permalink
refactor: 使用ReflectMetadata处理数据
Browse files Browse the repository at this point in the history
  • Loading branch information
bangbang93 committed Jun 7, 2023
1 parent aa97c2e commit a544a28
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 42 deletions.
10 changes: 5 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -32,7 +32,7 @@ export type RichModelType<T extends Constructor<object>, THelper = object> = Mod
export type Ref<T extends {_id?: unknown}> = T['_id'] | T
export type RefDocument<T extends {_id?: unknown}> = T['_id'] | DocumentType<T>

const modelCache = new WeakMap<Class<unknown>, RichModelType<IMongooseClass>>()
const modelCache = new WeakMap<Class<object>, Model<object>>()
const schemaCache = new WeakMap<MongooseMeta, Schema>()

export function getSchema<T>(modelClass: Class<T>): Schema {
Expand All @@ -51,9 +51,9 @@ export function getModel<T extends Constructor<object>>(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<T>
modelCache.set(modelClass, newModel as unknown as RichModelType<IMongooseClass>)
return newModel
const newModel = model(meta.name, getSchema(modelClass))
modelCache.set(modelClass, newModel)
return newModel as unknown as RichModelType<T>
}

export function getModelName<T extends Constructor<object>>(modelClass: T): string {
Expand Down
24 changes: 13 additions & 11 deletions src/meta.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<MongooseMeta>): 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<unknown> {
return Reflect.hasMetadata(mongooseMeta, target)
}
46 changes: 20 additions & 26 deletions src/schema.ts
Original file line number Diff line number Diff line change
@@ -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<T>(options: SchemaTypeOptions<T> = {},
Expand All @@ -17,29 +17,21 @@ export function prop<T>(options: SchemaTypeOptions<T> = {},
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<T>(type: T, options?: SchemaTypeOptions<T[]>) {
export function array<T extends Constructor<unknown>>(type: T, options?: SchemaTypeOptions<T[]>) {
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]
Expand Down Expand Up @@ -81,11 +73,13 @@ export function defaults<T extends DefaultType<unknown>>(value: T) {
}
}

export function type(type: unknown) {
export function type(type: Constructor<unknown>) {
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}
Expand All @@ -105,8 +99,8 @@ export function enums<T extends EnumValue>(values: Array<T> | Record<string | nu
type LazyClass = () => Constructor<unknown>

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<unknown>, idType?: unknown): (target: object, name: string) => void
export function ref(nameOrClass: string | Constructor<unknown> | LazyClass,
idType?: unknown): (target: object, name: string) => void {
if (typeof nameOrClass === 'string') {
return (target: object, name: string) => {
Expand Down Expand Up @@ -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<unknown>, elementType: unknown) {
if (typeof nameOrClass === 'string') {
return (target: object, name: string) => {
getMongooseMeta(target).schema[name] = {
Expand Down Expand Up @@ -194,19 +188,19 @@ export function refArray(nameOrClass: string | LazyClass | IMongooseClass, eleme
}

export function statics() {
return (target: Constructor<object>, 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<object>, 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<object>, name: string, descriptor: PropertyDescriptor) => {
return (target: object, name: string, descriptor: PropertyDescriptor) => {
getMongooseMeta(target).methods[name] = descriptor.value
}
}
Expand Down

0 comments on commit a544a28

Please sign in to comment.